This error is Safari’s way of saying, “you’re trying to use an iOS app WebView bridge… but you’re not in an iOS app WebView.”

window.webkit.messageHandlers is the JavaScript API for talking from a page loaded inside WKWebView back to native code. The native app registers a handler name, and JavaScript can call window.webkit.messageHandlers.<name>.postMessage(...). Here’s how Apple documents the contract.

When Safari throws:

undefined is not an object (evaluating 'window.webkit.messageHandlers')

…it means your code ran in an environment where that bridge simply does not exist.

The Problem

Some code on your page is doing this:


// This only works inside a WKWebView where the native app
// has registered the handler name
window.webkit.messageHandlers.nativeBridge.postMessage({
  type: "hello",
  payload: { ok: true }
});

On a normal website in Safari (and always in Chrome, Firefox, or Edge), window.webkit is usually missing, or messageHandlers is missing, so this explodes.

What’s Actually Happening

This error almost always means you shipped WKWebView-specific code into a context where it does not belong.

The most common case is shared code between a normal website and an iOS app that embeds the site in a WKWebView. The bridge works fine inside the app, then regular Safari users hit the same code path and everything falls apart.

Another frequent source is third-party or hybrid tooling that assumes it’s running inside an in-app browser. Cordova is a classic example, it uses window.webkit.messageHandlers.cordova.postMessage(...) when running in WKWebView mode, and fails loudly if that bridge is missing. There are plenty of bug reports that boil down to exactly this mismatch, like this one on GitHub.

Even inside a WKWebView, this error can happen if your native app forgot to register the handler, registered it under a different name, or registered it too late. JavaScript only gets messageHandlers.<name> if native code registered that exact name via WKUserContentController. Apple documents that setup here.

How to Fix It

Guard the call with feature detection

If your code runs on both the open web and inside an app, this is non-negotiable.


function postToNative(handlerName, message) {
  const bridge =
    window.webkit &&
    window.webkit.messageHandlers &&
    window.webkit.messageHandlers[handlerName] &&
    typeof window.webkit.messageHandlers[handlerName].postMessage === "function";

  if (!bridge) {
    // Not in WKWebView, or handler not registered.
    // Decide what "web fallback" means for your app.
    return false;
  }

  window.webkit.messageHandlers[handlerName].postMessage(message);
  return true;
}

// Usage
postToNative("nativeBridge", { type: "hello" });

If you’re using modern JavaScript, optional chaining makes this a lot cleaner:


if (window.webkit?.messageHandlers?.nativeBridge?.postMessage) {
  window.webkit.messageHandlers.nativeBridge.postMessage({ type: "hello" });
}

If you own the iOS app, verify the native side

Your JavaScript can be perfect and this will still fail if the app didn’t register the handler correctly.

The handler name must match exactly, and it must be registered before the page runs code that calls postMessage. Here’s Apple’s reference for that registration step.

Monitor your production errors

This one is famously environment-specific. Some users are inside an app, most are not. You want to know how often this is happening, which pages trigger it, and whether it correlates with real user pain.

That’s why you monitor production errors instead of guessing. Using something like TrackJS makes it obvious whether this is a broken integration you need to fix, or harmless noise from a context you don’t support.

When You Can Ignore It

You can usually ignore this error if it’s clearly coming from third-party code you don’t control, it only affects optional in-app features, and it isn’t impacting real users. If it’s tied to critical flows like auth, payments, or navigation inside your app, it’s not ignorable. That’s a real bug.

Summary

window.webkit.messageHandlers only exists inside WKWebView when native code registers a handler. If you try to use it on the open web, Safari throws:

undefined is not an object (evaluating 'window.webkit.messageHandlers')

Fix it with feature detection, and if you control the native app, make sure the handler is registered correctly and early. Then watch it in production so you know whether it actually matters.

TrackJS is the easy way to monitor your JavaScript applications and fix production errors. TrackJS is provides detailed error monitoring and alerting to developers around the world at companies like 3M, Tidal, IKEA, Venmo, Allbirds, and Frontend Masters. TrackJS catches millions of errors from users everyday. Let's start catching yours.

Protect your JavaScript