Setting up cross-origin isolation with COOP and COEP
Cross-origin isolation is an opt-in browser state that unlocks privileged APIs like SharedArrayBuffer, performance.measureUserAgentSpecificMemory(), and higher-precision timer access. The state also blocks document.domain mutations, closing a known gap in the same-origin policy.
To enter this isolated state, serve these headers on the main document:
Cross-Origin-Embedder-Policy: require-corp Cross-Origin-Opener-Policy: same-origin
These headers make the browser refuse resources and iframes that haven't explicitly opted in to cross-origin embedding, and prevent cross-origin windows from interacting with your document. Resources loaded from other origins therefore need to carry their own opt-in headers. You can verify the isolated state at runtime with self.crossOriginIsolated.
Terminology
Several similar-sounding policies are involved in isolation; here's what they stand for:
- COEP — Cross Origin Embedder Policy
- COOP — Cross Origin Opener Policy
- CORP — Cross Origin Resource Policy
- CORS — Cross Origin Resource Sharing
- CORB — Cross Origin Read Blocking
Enabling isolation step by step
1. Send Cross-Origin-Opener-Policy: same-origin
With COOP: same-origin on the top-level page, the document is placed in its own browsing context group, separate from any windows it opens or that open it, unless those windows share the same origin and the same COOP setting. That separation disables direct communication between the document and windows it no longer shares a context group with.
A browsing context group is a cluster of windows that can reference one another, such as a top-level page and the documents inside its iframes. If https://a.example opens a dialog at https://b.example, both windows normally share the same browsing context and can interchange references through DOM APIs like window.opener.

DevTools shows whether a window opener and its opened window ended up in separate context groups.
2. Serve CORP or CORS on all resources
Every subresource in the page must be loadable under either CORP or CORS before you enable COEP. Set headers based on the resource's intended audience:
- Same origin only — use
Cross-Origin-Resource-Policy: same-origin. - Same site, possibly cross origin — use
Cross-Origin-Resource-Policy: same-site. - Under your control, cross origin — use
Cross-Origin-Resource-Policy: cross-originwhen possible. - Cross origin, not under your control — add the
crossoriginattribute to the loading tag if the resource supports CORS (for example,<img src="..." crossorigin>), or ask the owner to send CORS or CORP headers. - Iframes — apply the same privacy rules:
cross-origin,same-site, orsame-origindepending on context. - Workers — scripts for
WebWorkermust be same-origin, so CORP/CORS headers aren't needed. - Under COEP: require-corp — any cross-origin subresource loaded without CORS must send
Cross-Origin-Resource-Policy: cross-originto be embeddable. This applies to<script>,importScripts,<link>,<video>,<iframe>, and more.
Isolation inside iframes
A frame embedded with <iframe allow="cross-origin-isolated"> can have its own cross-origin isolated state, but the whole document chain — parent and child frames — must also be isolated.
3. Dry run with the Report-Only header
Before enforcing COEP, test with Cross-Origin-Embedder-Policy-Report-Only. This header reports violations without blocking any content. Apply it to every document in the chain — top-level page, iframes, and worker scripts — and watch for issues using the Reporting API.
4. Enable COEP
Once resource headers are confirmed and no Report-Only violations remain, swap Cross-Origin-Embedder-Policy-Report-Only for the enforcement version: Cross-Origin-Embedder-Policy. Use the same value on all documents, including embedded frames and workers.
Verifying the result
When isolation is active, self.crossOriginIsolated returns true. This confirms the page and all of its windows and resources are inside the same isolated browsing context group, and APIs such as performance.measureUserAgentSpecificMemory() are available.
Troubleshooting
Using Chrome DevTools
Visually blocked resources like images are easy to spot: the request fails and a broken image renders. For invisible resources, like scripts or stylesheets, open the Network panel. COEP failures appear in the Status column with (blocked:NotSameOriginAfterDefaultedToSameOriginByCoep).

Clicking the entry exposes more detail. The Application panel's Frames section, under the "top" expandable, shows per-frame isolation status, including availability of SharedArrayBuffer, and the same for dialogs opened from your page.



Watching reports with the Reporting API
The Reporting API lets a browser send a report whenever COEP blocks a resource or COOP isolates a window. Chrome has supported the API since version 69. Configure a report endpoint and server to receive these events. Example report payloads for blocked cross-origin resources and opened-in-isolation dialogs look as follows:
[{ "age": 25101, "body": { "blocked-url": "https://third-party-test.glitch.me/check.svg?", "blockedURL": "https://third-party-test.glitch.me/check.svg?", "destination": "image", "disposition": "enforce", "type": "corp" }, "type": "coep", "url": "https://cross-origin-isolation.glitch.me/?coep=require-corp&coop=same-origin&", "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4249.0 Safari/537.36" }]
[{ "age": 7, "body": { "disposition": "enforce", "effectivePolicy": "same-origin", "nextResponseURL": "https://third-party-test.glitch.me/popup?report-only&coop=same-origin&", "type": "navigation-from-response" }, "type": "coop", "url": "https://cross-origin-isolation.glitch.me/coop?coop=same-origin&", "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4246.0 Safari/537.36" }]
In Report-Only mode, COOP also signals attempts to access across different browsing context groups — for instance, a postMessage() call would generate a report like this:
[{ "age": 51785, "body": { "columnNumber": 18, "disposition": "reporting", "effectivePolicy": "same-origin", "lineNumber": 83, "property": "postMessage", "sourceFile": "https://cross-origin-isolation.glitch.me/popup.js", "type": "access-from-coop-page-to-openee" }, "type": "coop", "url": "https://cross-origin-isolation.glitch.me/coop?report-only&coop=same-origin&", "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4246.0 Safari/537.36" }, { "age": 51785, "body": { "disposition": "reporting", "effectivePolicy": "same-origin", "property": "postMessage", "type": "access-to-coop-page-from-openee" }, "type": "coop", "url": "https://cross-origin-isolation.glitch.me/coop?report-only&coop=same-origin&", "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4246.0 Safari/537.36" }]
Cross-origin isolation is the combination of these COOP and COEP headers, with self.crossOriginIsolated acting as the final check that the environment is set up correctly.
Changelog highlights
Cross-origin isolation has evolved significantly since its initial rollout. The following updates track the key changes to browser support and API availability:
- June 21, 2022: Worker scripts also need care when cross-origin isolation is enabled.
- Aug 5, 2021: The JS Self-Profiling API has been removed from the list of APIs requiring cross-origin isolation, following a change in its specification direction.
- May 6, 2021: The restriction timeline for
SharedArrayBufferon non-cross-origin-isolated sites was adjusted for Chrome M92 based on community feedback. - April 16, 2021: Notes were added regarding COEP credentialless mode and the relaxed condition allowing COOP
same-origin-allow-popupsfor cross-origin isolation. - March 5, 2021: Removed limitations for
SharedArrayBuffer,performance.measureUserAgentSpecificMemory(), and debugging in Chrome 89. Higher precision forperformance.now()andperformance.timeOriginwas listed as an upcoming capability. - February 19, 2021: Added details on the feature policy
allow="cross-origin-isolated"and corresponding DevTools debugging support. - October 15, 2020:
self.crossOriginIsolatedbecame available in Chrome 87. When it returnstrue,document.domainis immutable.performance.measureUserAgentSpecificMemory()ended its origin trial and is enabled by default in Chrome 89.SharedArrayBufferon Android Chrome became available from Chrome 88.



