v150 · Security · demo

Migration Patterns

Three common patterns that break when data: URL workers gain opaque origins in Chrome 150 — and their drop-in replacements using Blob URLs. The worker logic stays the same; only the URL construction changes.

BroadcastChannel between page and data: URL worker breaks in Chrome 150
Before — data: URL worker (broken)
// main page const ch = new BroadcastChannel('bus'); const src = ` // worker — opaque origin in Chrome 150 const ch = new BroadcastChannel('bus'); // ↑ BroadcastChannels are origin-scoped. // With an opaque origin this creates a // DIFFERENT channel — messages never arrive. ch.postMessage('hello from worker'); `; const w = new Worker( 'data:text/javascript,' + encodeURIComponent(src) ); // ch.onmessage never fires in Chrome 150
After — Blob URL worker (fixed)
// main page const ch = new BroadcastChannel('bus'); const src = ` // worker — inherits page origin via blob: const ch = new BroadcastChannel('bus'); ch.postMessage('hello from worker'); `; const blob = new Blob([src], { type: 'text/javascript' }); const url = URL.createObjectURL(blob); const w = new Worker(url); URL.revokeObjectURL(url); // clean up // ✓ ch.onmessage fires — same origin
BroadcastChannel partitions messages by origin. A channel named "bus" on your page and the same channel in an opaque-origin worker are different channels — messages in one never reach the other. Use a blob: URL so the worker inherits the page's origin, or switch from BroadcastChannel to a direct postMessage channel which does not require same-origin.
not run
Runs a data: URL worker and a Blob URL worker on fresh BroadcastChannel names, then waits to see which messages reach the page.
IndexedDB access in a data: URL worker breaks in Chrome 150
Before — data: URL worker (broken)
const src = ` // Chrome 149: worker has page origin // Chrome 150: SecurityError on open() const req = indexedDB.open('mydb'); req.onsuccess = () => { const db = req.result; // do work with db }; req.onerror = (e) => postMessage({ error: e.target.error }); `; new Worker( 'data:text/javascript,' + encodeURIComponent(src) ); // ↑ throws SecurityError in Chrome 150
After — Blob URL worker (fixed)
const src = ` // Blob URL worker: inherits page origin const req = indexedDB.open('mydb'); req.onsuccess = () => { const db = req.result; // do work with db }; req.onerror = (e) => postMessage({ error: e.target.error }); `; const blob = new Blob([src], { type: 'text/javascript' }); const url = URL.createObjectURL(blob); new Worker(url); URL.revokeObjectURL(url); // ✓ IndexedDB access works normally
indexedDB, localStorage, sessionStorage, and caches (Cache API) all require a non-opaque, non-cross-origin origin to function. Workers with an opaque origin receive a SecurityError when opening any of these APIs. Switching to a blob: URL restores the page's origin and full storage access.
not run
Opens a disposable IndexedDB database from both worker URL schemes and reports the observed success or SecurityError path.
Inline worker with importScripts() breaks in Chrome 150
Before — data: URL + importScripts (broken)
// Tries to import a same-origin script from // inside a data: URL worker. In Chrome 150 // the worker has an opaque origin, so this // helper becomes a cross-origin load. const helperUrl = new URL('/lib/utils.js', location.href).href; const src = ` importScripts(${JSON.stringify(helperUrl)}); // ↑ SecurityError/NetworkError once the // data: worker origin is opaque postMessage(compute()); `; new Worker( 'data:text/javascript,' + encodeURIComponent(src) );
After — Blob URL worker (fixed)
// Resolve helper URLs on the page, then embed // the absolute same-origin URL into the worker. const helperUrl = new URL('/lib/utils.js', location.href).href; const src = ` importScripts(${JSON.stringify(helperUrl)}); // ✓ same-origin from the Blob worker postMessage(compute()); `; const blob = new Blob([src], { type: 'text/javascript' }); const url = URL.createObjectURL(blob); new Worker(url); URL.revokeObjectURL(url);
Resolve helper script URLs on the page before stringifying worker source. In Chrome 150 a data: URL worker has an opaque origin, so same-origin helper loads become cross-origin and can fail. A blob: URL worker keeps the page origin, so the pre-resolved helper URL remains same-origin and importScripts() can load it.
not run
Imports the local helper.js file from each worker and shows whether the helper function can run.
API / Pattern data: URL worker (Chrome 150) blob: URL worker (any Chrome)
self.origin "null" (opaque) page's origin
BroadcastChannel isolated — wrong channel same as page
IndexedDB SecurityError accessible
Cache API SecurityError accessible
importScripts(helperUrl) cross-origin / opaque same-origin helper loads
postMessage to parent works (not origin-gated) works
fetch() works (absolute URLs) works

see also

implementation reference

Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗