Cross-origin isolation
Why
The Wavelength SDK’s default transport runs the wallet daemon in a Web Worker and stores
encrypted wallet data in OPFS-backed SQLite. Both the worker’s WASM module and
the SQLite stack use SharedArrayBuffer for efficient memory sharing.
Browsers gate SharedArrayBuffer behind cross-origin isolation: the page
must be served with headers that prevent other origins from reading its memory.
Without isolation, SharedArrayBuffer is unavailable, OPFS persistence fails,
and the worker transport cannot start.
Cross-origin isolation is a web-only concern. It applies to every route in your app that loads the Wavelength SDK, including embedded demo or playground pages on the docs site.
COOP/COEP headers
These are response headers on your own HTML document, so only the server that serves your app can set them. The Wavelength SDK cannot set them for you: they are not something the SDK, the worker, or the runtime assets can emit on their own. Send them on wallet routes (and on your dev server while testing locally):
Cross-Origin-Opener-Policy: same-originCross-Origin-Embedder-Policy: require-corpCross-Origin-Opener-Policy: same-origin keeps other browsing contexts from
holding a reference to your page’s global object.
Cross-Origin-Embedder-Policy: require-corp requires every subresource
(script, stylesheet, image, font, WASM) to either be same-origin or explicitly
opt in with Cross-Origin-Resource-Policy: cross-origin (or be loaded with
crossorigin where applicable). Same-origin assets need no extra attribute.
Scope headers to embed routes. If only part of your site runs the wallet
(for example /web/playground/* on the docs site), apply COOP/COEP on those
paths rather than the entire domain. Hosts like Netlify and Cloudflare Pages read
a _headers file:
/web/playground/* Cross-Origin-Opener-Policy: same-origin Cross-Origin-Embedder-Policy: require-corpFor Vite during local development, set the same headers on the dev and preview servers:
const crossOriginIsolation = { 'Cross-Origin-Opener-Policy': 'same-origin', 'Cross-Origin-Embedder-Policy': 'require-corp', 'Cross-Origin-Resource-Policy': 'same-origin',};
export default defineConfig({ server: { headers: crossOriginIsolation }, preview: { headers: crossOriginIsolation },});Self-host third-party assets. Cross-origin Google Fonts, analytics scripts,
and similar embeds are blocked under require-corp. Bundle fonts locally (for
example with @fontsource) or serve them from the same origin as your app.
Optional: credentialless COEP. Some teams use
Cross-Origin-Embedder-Policy: credentialless as a lighter alternative. It is
not supported uniformly across browsers (Safari in particular). The Wavelength SDK targets
require-corp because every major engine supports it today. The key
difference: credentialless drops credentials (cookies, client certificates)
on cross-origin requests instead of requiring the target origin to opt in with
Cross-Origin-Resource-Policy.
Verify with curl. After deploying, confirm the headers are present:
curl -sI https://your-app.example/web/playground/ | grep -i cross-originYou should see both Cross-Origin-Opener-Policy: same-origin and
Cross-Origin-Embedder-Policy: require-corp (or credentialless if you chose
that mode).
In the browser, open DevTools and check that
crossOriginIsolated is true:
console.log(crossOriginIsolated); // trueIf isolation is missing, the wallet will fail to initialize the OPFS database. See Troubleshooting for common fixes.