Today WebView Bridge

Introduction

The typed, promise-based message channel between embedded web content and the native host.

The Today WebView Bridge is the contract that lets Today web content rendered inside a native WebView talk to its host application. It is a single, typed, promise-based message channel. Web code calls into host-provided capabilities (analytics, request headers, token refresh); the host answers asynchronously.

The npm package @today/webview-bridge is the web-side client for this channel. iOS, macOS (WKWebView), Android, and Windows (WebView2) hosts implement the matching native side.

Why a bridge exists

A native WebView can only decorate the document navigation request — on iOS, that is the one WKNavigationDelegate.decidePolicyFor(navigationAction) callback that fires for the top-level page load. Once the page is running, the fetch / XHR requests a single-page app issues are subresource requests: they never pass through that callback, and there is no public WebView API to rewrite their headers.

So the host cannot transparently inject an Authorization header into the web app's own requests. The bridge inverts the flow: instead of the host pushing headers onto requests it cannot see, the web asks the host for the headers and attaches them itself. The headers and refreshToken capabilities exist entirely to serve this pattern; track rides the same channel for analytics.

If authentication travelled on a cookie instead of an Authorization header, no bridge would be needed — the WebView attaches same-origin cookies to fetch/XHR automatically. The bridge is specifically for header-based (Bearer) auth, which the browser will not carry on its own.

How to read these docs

  • Web SDK — the reference for the web side: how to install @today/webview-bridge, the full client API, the authenticated-fetch pattern, and the TypeScript surface. Start here if you are writing web code.
  • Contract — the transport-agnostic specification: the message envelope, every capability's request and result shape, error semantics, and versioning rules. This is the source of truth that every platform implements against.
  • Native Reference — non-normative guidance for host implementers: how iOS, macOS, Android, and Windows satisfy the contract. Read this if you are building the native side.

At a glance

CapabilityDirectionAwaitPurpose
trackweb → nativenoFire-and-forget analytics, forwarded to PostHog
headersweb → nativeyesFetch the headers web must attach to its own fetch / XHR
refreshTokenweb → nativeyesForce a token refresh after a 401
establishSessionweb → nativeyesHost mints the session cookie natively; bearer never reaches JS

Alongside these message capabilities, the SDK exposes platform ('ios' | 'android' | 'macos' | 'windows' | 'web') — resolved synchronously, not over the channel, because it is static and needed before first paint.

The runtime channel is named todayWebViewBridge. On iOS it is reached through window.webkit.messageHandlers.todayWebViewBridge; on Android through an injected window.todayWebViewBridge object. The SDK hides this difference — application code only ever touches the @today/webview-bridge client.

On this page