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
- Origin Isolation Demo — live test in your browser
- Back to feature index
- ChromeStatus entry
implementation reference
Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗