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
Authorizationheader, no bridge would be needed — the WebView attaches same-origin cookies tofetch/XHRautomatically. 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
| Capability | Direction | Await | Purpose |
|---|---|---|---|
track | web → native | no | Fire-and-forget analytics, forwarded to PostHog |
headers | web → native | yes | Fetch the headers web must attach to its own fetch / XHR |
refreshToken | web → native | yes | Force a token refresh after a 401 |
establishSession | web → native | yes | Host 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.