browser-support
Browser support
Which browsers the browser backend runs in, what headers your page must serve, and what degrades when isolation isn't available.
The browser backend uses SharedArrayBuffer for its synchronous virtual
filesystem, which means your page must be cross-origin isolated.
Without the right headers, the browser runtime degrades to a partial
mode or refuses to boot.
The server backend does not depend on browser OPFS or
SharedArrayBuffer, but the page still needs normal browser support for
the SDK, fetch, and WebSocket transport.
Required headers
Your page must respond with:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
…and every same-origin asset must respond with:
Cross-Origin-Resource-Policy: same-origin
Once all three are present, globalThis.crossOriginIsolated evaluates to
true and SharedArrayBuffer becomes available.
Firefox is strict about CORP. Without Cross-Origin-Resource-Policy: same-origin on every sub-resource, Firefox blocks access to
SharedArrayBuffer even when the page itself is cross-origin isolated.
Chromium tolerates the omission today; Firefox does not. Set CORP
everywhere.
Configuring Next.js
// next.config.ts
export default {
async headers() {
return [
{
source: '/your-runtime-route/:path*',
headers: [
{ key: 'Cross-Origin-Opener-Policy', value: 'same-origin' },
{ key: 'Cross-Origin-Embedder-Policy', value: 'require-corp' },
],
},
{
source: '/_next/static/:path*',
headers: [{ key: 'Cross-Origin-Resource-Policy', value: 'same-origin' }],
},
];
},
};
Scope the COOP / COEP headers to the routes that actually need Verklet —
they break third-party <iframe> and <img> embeds that don't return
CORP headers themselves.
Preview CSP
Runtime previews use isolated subdomains under
https://*.preview.verklet.com. If your CSP restricts frames, add that
wildcard to frame-src and, for older browsers, child-src. SDK calls
through runtime.fetchPreview() are routed inside the runtime and do not
require browser network access to the preview domain.
Browser matrix
| Feature | Chromium | WebKit | Firefox |
|---|---|---|---|
| Boot runtime | supported | supported | supported |
| Spawn Node process | supported | supported | supported |
| Spawn Python process (Pyodide) | supported | unknown² | unknown² |
Synchronous fs from worker (SyncVfs / SAB) | supported | supported | supported |
| OPFS project persistence | supported | partial¹ | supported |
| OPFS persistence: reload + restore | supported | partial¹ | supported |
| OPFS persistence: cross-tab handoff | supported | unknown² | unknown² |
| Service Worker preview routing | supported | unknown² | unknown² |
| HMR / WebSocket preview bridge | supported | unknown² | unknown² |
Footnotes
-
WebKit OPFS — Real Safari supports OPFS, but Playwright's WebKit build throws
UnknownErroron the firstnavigator.storage.getDirectory()call. The runtime detects this via an availability probe at boot and setscapabilities.opfs = falserather than crashing. Persist+restore skips cleanly when OPFS is unavailable. -
Unknown — The feature has not yet been exercised by the cross-browser smoke harness. Behaviour may differ from Chromium; explicit testing is needed before marking the cell
supportedorpartial.
Detecting capabilities
If you need to render a fallback when the host can't support Verklet:
import { detectCapabilities } from '@verklet/sdk';
const caps = await detectCapabilities();
if (!caps.crossOriginIsolated || !caps.sharedArrayBuffer) {
// show a "open in a modern browser" message, or a static fallback
}