Capture Javascript Errors From a WKWebView in Swift

A WKWebView is a great tool for integrating the web into iOS and macOS apps. Often debugging the webpage running inside a WKWebView can be challenging. This post presents two methods for getting error messages from a WKWebView:

  1. Capture Javascript Errors From A WKWebView Using Message Handlers
  2. Capture Javascript Errors From A WKWebView Using The Safari Web Inspector

Enable Javascript For A WKWebView

Capturing Javascript messages requires Javascript to be enabled on the WKWebView configuration. You can ensure Javascript is enabled using:

webKitView?.configuration.preferences.javaScriptEnabled = true

Capture Javascript Errors From A WKWebView Using Message Handlers

One method to capture Javascript errors from a WKWebView uses WKScriptMessageHandler and WKUserContentController. First, create a WKScriptMessageHandler by calling the add(_:, name:) method on the WKWebView.userControllerController:

// Create a WKScriptMessageHandler named "error"
let controller = webKitView?.configuration.userContentController
controller?.add(self, name: "error")

Next, to handle message sent by a WKScriptMessageHandler adhere to the WKScriptMessageHandler protocol and implement the userContentController(_: didReceive:) method:

extension ViewController: WKScriptMessageHandler {
    // Called for messages received by 
    // WKWebView message handlers
    func userContentController(
        _ userContentController: WKUserContentController, 
        didReceive message: WKScriptMessage) {

        // The WKScriptMessageHandler name 
        // of the sender is message.name
        if message.name == "error" {
            // Parse the response object to obtain the error
            let body = message.body as? [String: Any]
            let error = body?["message"] as? String
            print(error)
        }
    }
}

Inside of your web application, you can post messages to WebKit message handlers using the window.webkit.messageHandlers object. Since a WKScriptMessageHandler was created called "error", use window.webkit.messageHandlers.error.postMessage to send messages.

To test the implementation, inject a WKUserScript when the document starts that calls postMessage with a message object:

// Create a WKUserScript
let errorScript = WKUserScript(
    source:
"""
window.webkit.messageHandlers.error.postMessage({
    message: "An error occurred."
});
""",
    injectionTime: .atDocumentStart,
    forMainFrameOnly: true
)

// Add errorScript to the WKWebView by calling
// userControllerController.addUserScript
let controller = webKitView?.configuration.userContentController
controller?.addUserScript(errorScript)

WKWebView Error Messages Only Contain “Script Error.”

WKScriptMessageHandler is best suited for web applications that you develop. Calling window.webkit.messageHandlers.error.postMessage inside of the window.onerror callback will return detailed error objects only for scripts loaded by the origin, not injected WKUserScript scripts.

If you try to inject a WKUserScript with a window.onerror callback using message handlers, all errors will return only “Script Error”. The reason is web page security, as described on developer.mozilla.org:

When an error occurs in a script, loaded from a different origin, the details of the error are not reported to prevent leaking information (see bug 363897). Instead the error reported is simply "Script error."

Capture Javascript Errors From A WKWebView Using The Safari Web Inspector

The Safari Web Inspector is the best choice to debug WKWebView error messages for webpages that you do not control. Follow these steps to open the Safari Web Inspector during app development:

1. Run your application on your iPhone, iPhone Simulator, iPad, iPad Simulator, or Mac. If using an iPhone or iPad, make sure the device is connected to your computer and recognized as a development device.

2. Open Safari Preferences and ensure "Show Develop menu in menu bar" is enabled

Safari Preferences, Advanced Menu showing "Show Develop menu in menu bar" enabled
  1. In the develop menu select the WKWebView inside of the application you want to inspect
Safari Navigation Develop Menu showing an available WKWebView inside of a running app on an iPhone 8 simulator

4. Look at the Safari Web Inspector console to find more information about the errors that occurred on the loaded web page

Safari Web Inspector showing a Javascript error captured in the console

Get Javascript Errors From WKWebView on iOS and macOS in Swift

That’s it! Using WKScriptMessageHandler and the Safari Web Inspector you are well equipped to debug Javascripts errors that occur in WKWebView pages.