Cross-Origin Isolation
Configure Cross-Origin-Opener-Policy (COOP) and Cross-Origin-Embedder-Policy (COEP) reporting to safely deploy cross-origin isolation and enable powerful browser features like SharedArrayBuffer.
New to cross-origin isolation? Read our Cross-Origin Isolation overview to understand the benefits before diving into configuration.
What is Cross-Origin Isolation?
Cross-origin isolation is a browser security state achieved by deploying two HTTP headers together: Cross-Origin-Opener-Policy (COOP) and Cross-Origin-Embedder-Policy (COEP). When both headers are configured correctly, your page runs in an isolated browsing context that unlocks powerful features while protecting users from side-channel attacks like Spectre.
COOP controls how your document interacts with cross-origin windows opened via
window.open() or navigations. When set to same-origin, your page runs in its own process
group, isolated from cross-origin documents that might try to exploit shared memory or timing attacks.
COEP ensures that every cross-origin resource your page loads has explicitly opted in via CORS or
the Cross-Origin-Resource-Policy header. This prevents attackers from using your site to probe
cross-origin data through speculative execution attacks.
Together, these headers enable crossOriginIsolated — a secure state that unlocks
SharedArrayBuffer, high-precision timers (5 microseconds vs 100 microseconds), and
performance.measureUserAgentSpecificMemory().
Specification
Cross-Origin-Opener-Policy (COOP):
- HTML Living Standard: COOP — Official specification
- MDN: Cross-Origin-Opener-Policy — Developer documentation
Cross-Origin-Embedder-Policy (COEP):
- HTML Living Standard: COEP — Official specification
- MDN: Cross-Origin-Embedder-Policy — Developer documentation
Browser Support
Cross-origin isolation has excellent browser support, with COOP at 91.9% and COEP at 92.36% global coverage.
| Browser | COOP Support | COEP Support |
|---|---|---|
| Chrome | 83+ | 83+ |
| Edge | 83+ | 83+ |
| Firefox | 79+ | 79+ |
| Safari | 15.2+ | 15.2+ |
Why Monitor COOP/COEP Violations?
Cross-origin isolation unlocks powerful capabilities, but deploying COOP and COEP can break critical integrations. Monitoring violations before enforcement is essential:
- Identify breaking integrations — OAuth popups, payment gateways, and cross-origin windows can lose communication when COOP is enforced
-
Discover missing CORP headers — Third-party resources without
Cross-Origin-Resource-Policyheaders are blocked by COEP - Test policies safely — Report-Only mode shows what would break without affecting users
-
Enable powerful features — Access
SharedArrayBuffer, precise timers, and memory measurement APIs - Protect against Spectre — Isolate your application from side-channel attacks
Who Benefits
- Platform architects — Enable WebAssembly threading and high-performance computation
- Security engineers — Mitigate Spectre-class vulnerabilities in sensitive applications
- Performance engineers — Unlock precise timing APIs for accurate performance measurement
- Game developers — Enable multi-threaded WebAssembly for complex games and simulations
When to Enable
Cross-origin isolation is required if you need:
SharedArrayBufferfor multi-threaded WebAssembly or worker communication- High-precision
performance.now()timers (5μs vs 100μs resolution) performance.measureUserAgentSpecificMemory()for memory profiling
Even if you don't need these features today, consider enabling Report-Only mode to understand your application's cross-origin dependencies and prepare for future requirements.
How to Configure
Step 1: Set Up the Reporting Endpoint
First, define where browsers should send violation reports using the Reporting-Endpoints header:
Reporting-Endpoints: default="https://reporting-api.app/browser-reports/YOUR-ENDPOINT-UUID"
Replace YOUR-ENDPOINT-UUID with your application's unique endpoint from the
reporting-api.app dashboard.
Step 2: Enable COOP Report-Only Mode
Before enforcing COOP, test it using the Cross-Origin-Opener-Policy-Report-Only header. This sends
violation reports without breaking cross-origin window interactions:
Cross-Origin-Opener-Policy-Report-Only: same-origin; report-to="default"
COOP Report-Only mode helps you identify:
- OAuth popups that would lose communication with your page
- Payment gateways using popup windows
- Third-party widgets that rely on
window.opener
Step 3: Enable COEP Report-Only Mode
Similarly, test COEP with the Cross-Origin-Embedder-Policy-Report-Only header:
Cross-Origin-Embedder-Policy-Report-Only: require-corp; report-to="default"
COEP Report-Only mode reveals cross-origin resources that would be blocked, including:
- Images, scripts, and stylesheets from CDNs without CORP headers
- Iframes embedding third-party content
- API requests made without CORS
Cross-Origin-Opener-Policy-Report-Only and
Cross-Origin-Embedder-Policy-Report-Only simultaneously. This gives you a complete picture of what will
break when you enable cross-origin isolation.
Step 4: Monitor Reports and Prepare Resources
After deploying Report-Only mode, monitor incoming reports in your dashboard. For each blocked resource, you have several options:
For resources you control:
- Add
Cross-Origin-Resource-Policy: cross-originheader to allow embedding - Or add
Cross-Origin-Resource-Policy: same-sitefor same-site embedders only
For third-party resources:
- Add
crossoriginattribute to enable CORS mode:<img src="..." crossorigin> - Request CORP header support from the resource provider
- Consider using
credentiallessCOEP mode (see below)
For cross-origin popups (OAuth, payments):
- Use
same-origin-allow-popupsCOOP value to maintain popup communication - Or refactor to use redirect-based flows instead of popups
Step 5: Switch to Enforcement
Once you've resolved all issues identified in Report-Only mode, enable enforcement:
Cross-Origin-Opener-Policy: same-origin; report-to="default" Cross-Origin-Embedder-Policy: require-corp; report-to="default" Reporting-Endpoints: default="https://reporting-api.app/browser-reports/YOUR-UUID"
report-to="default" even after enforcement. This provides ongoing visibility into blocked
resources and helps catch regressions when dependencies change.
Step 6: Set Up Integrations
Route COOP and COEP violation reports to your existing tools for alerting and analysis:
- AppSignal integration — Track violations alongside application errors
- Webhook integration — Send reports to Slack, PagerDuty, or custom endpoints
- Google Chat integration — Post alerts to team chat spaces
See the Integrations documentation for setup instructions.
COOP Header Values
The Cross-Origin-Opener-Policy header accepts these values:
| Value | Effect |
|---|---|
unsafe-none |
Default. Allows sharing browsing context with cross-origin documents. No isolation. |
same-origin |
Strictest. Only same-origin documents with same-origin COOP share context. Enables cross-origin
isolation (with COEP). Breaks cross-origin popups.
|
same-origin-allow-popups |
Like same-origin, but allows popups with unsafe-none to maintain
window.opener. Useful for OAuth flows.
|
noopener-allow-popups |
Opens all navigations in new browsing context groups. Severs opener relationship. Most isolating for same-origin documents. |
SharedArrayBuffer, you must use
Cross-Origin-Opener-Policy: same-origin. The same-origin-allow-popups value does
not enable cross-origin isolation.
COEP Header Values
The Cross-Origin-Embedder-Policy header accepts these values:
| Value | Effect |
|---|---|
unsafe-none |
Default. Allows loading cross-origin resources without explicit permission. |
require-corp |
Strictest. Cross-origin resources must include Cross-Origin-Resource-Policy header or be loaded
via CORS. Enables cross-origin isolation (with COOP).
|
credentialless |
Allows cross-origin no-cors resources but strips credentials (cookies). Resources don't need
CORP headers. Enables cross-origin isolation (with COOP).
|
The credentialless Option
The credentialless value offers a middle ground when you can't get CORP headers on all third-party
resources:
Cross-Origin-Opener-Policy: same-origin; report-to="default" Cross-Origin-Embedder-Policy: credentialless; report-to="default" Reporting-Endpoints: default="https://reporting-api.app/browser-reports/YOUR-UUID"
With credentialless:
- Cross-origin
no-corsrequests are sent without cookies - Resources don't need
Cross-Origin-Resource-Policyheaders - CORS requests still require proper
Access-Control-Allow-Originheaders - Cross-origin isolation is still achieved (with
same-originCOOP)
credentialless when you need cross-origin isolation but can't modify third-party resources to add
CORP headers. Be aware that credentialless requests don't send cookies, which may break some integrations that
require authentication.
Understanding Violation Reports
COOP and COEP generate different report types. Understanding these helps you diagnose and fix issues.
COOP Report Fields
COOP violations are reported with type coop:
| Field | Description |
|---|---|
type |
Violation type: navigation-to-response, navigation-from-response, or access types
like access-to-opener
|
disposition |
enforce if enforced, reporting if Report-Only mode
|
effectivePolicy |
The COOP value that triggered the report |
previousResponseURL / nextResponseURL |
URL involved in the navigation (sanitized for cross-origin) |
property |
For access violations: the property accessed (e.g., postMessage)
|
COEP Report Fields
COEP violations are reported with type coep:
| Field | Description |
|---|---|
type |
Violation type: corp (blocked resource), navigation, or
worker initialization
|
blockedURL |
URL of the blocked resource |
disposition |
enforce if blocked, reporting if Report-Only mode
|
destination |
Request destination type (e.g., image, script, iframe)
|
Example Reports
{
"type": "coop",
"url": "https://example.com/app",
"body": {
"type": "access-to-opener",
"disposition": "reporting",
"effectivePolicy": "same-origin",
"property": "postMessage",
"sourceFile": "https://auth.example.com/callback.js",
"lineNumber": 42,
"columnNumber": 12
}
}
{
"type": "coep",
"url": "https://example.com/dashboard",
"body": {
"type": "corp",
"blockedURL": "https://cdn.example.com/image.png",
"disposition": "reporting",
"destination": "image"
}
}
Common Breakage Patterns
OAuth Popups
OAuth flows using popups (Google Sign-In, GitHub OAuth, etc.) break with strict COOP because
window.opener becomes null. Solutions:
-
Use
same-origin-allow-popups— Maintains popup communication but doesn't enable full cross-origin isolation - Use redirect-based flows — Refactor to use OAuth redirect instead of popup
- Accept the limitation — Some OAuth libraries handle this gracefully with fallback mechanisms
Payment Gateways
Stripe, PayPal, and other payment providers may use popups or iframes that break with COOP/COEP:
- Check provider documentation — Many providers have updated libraries that work with cross-origin isolation
- Use iframe-based flows — Some providers offer embedded checkout that may work better
- Test thoroughly in Report-Only mode — Identify specific issues before enforcement
Third-Party CDN Resources
Images, fonts, and scripts from CDNs may lack CORP headers:
-
Add
crossoriginattribute —<img src="..." crossorigin>enables CORS - Use
credentiallessCOEP — Allows loading without CORP headers - Self-host critical resources — Host your own copies of essential third-party resources
Verifying Cross-Origin Isolation
Check if your page has achieved cross-origin isolation using JavaScript:
if (self.crossOriginIsolated) {
console.log("Cross-origin isolated! SharedArrayBuffer is available.");
const buffer = new SharedArrayBuffer(1024);
// Use shared memory features
} else {
console.log("Not cross-origin isolated. Using fallback.");
const buffer = new ArrayBuffer(1024);
}
You can also check in Chrome DevTools:
- Open DevTools → Application → Frames
- Select the top frame
- Look for "Cross-Origin Isolated" status in the Security & Isolation section
Server Configuration Examples
Nginx
server {
# ... your existing configuration ...
# Reporting endpoint
add_header Reporting-Endpoints 'default="https://reporting-api.app/browser-reports/YOUR-UUID"' always;
# Cross-origin isolation with reporting
add_header Cross-Origin-Opener-Policy 'same-origin; report-to="default"' always;
add_header Cross-Origin-Embedder-Policy 'require-corp; report-to="default"' always;
}
Ruby on Rails
# Add cross-origin isolation headers with reporting # Note: Use lowercase header names for Rack 3 compatibility config.action_dispatch.default_headers.merge!( "reporting-endpoints" => 'default="https://reporting-api.app/browser-reports/YOUR-UUID"', "cross-origin-opener-policy" => 'same-origin; report-to="default"', "cross-origin-embedder-policy" => 'require-corp; report-to="default"' )
Apache
Header always set Reporting-Endpoints 'default="https://reporting-api.app/browser-reports/YOUR-UUID"' Header always set Cross-Origin-Opener-Policy 'same-origin; report-to="default"' Header always set Cross-Origin-Embedder-Policy 'require-corp; report-to="default"'
Troubleshooting
crossOriginIsolated is false
-
Check both headers — Cross-origin isolation requires both COOP
same-originAND COEPrequire-corporcredentialless - Check all frames — Every iframe in the page must also be cross-origin isolated
- Verify header syntax — Ensure headers are formatted correctly without typos
- Check Permissions-Policy —
cross-origin-isolatedmust not be blocked
Reports Not Appearing
-
Verify
report-todirective — Ensure headers includereport-to="default" -
Check
Reporting-Endpoints— The endpoint name must match (e.g.,default) - Check allowed origins — Ensure your website's origin is whitelisted in your application settings
- Wait for batching — Browsers batch reports; they may not appear immediately
Resources Blocked Unexpectedly
-
Check network tab — Look for
(blocked:NotSameOriginAfterDefaultedToSameOriginByCoep)errors - Add crossorigin attribute — Enable CORS for cross-origin resources
-
Use credentialless — Switch to
credentiallessCOEP if CORP headers aren't available -
Verify CORP headers — Check that third-party resources include
Cross-Origin-Resource-Policy
OAuth/Popup Communication Broken
-
Check COOP value —
same-originbreaks popup communication; considersame-origin-allow-popups - Review OAuth library — Some libraries support redirect-based flows as an alternative
- Accept tradeoff — You may need to choose between cross-origin isolation and popup-based OAuth
Next Steps
- Permissions Policy — Control browser feature access
- Integrations — Route reports to your observability tools
- Getting Started — Set up your first application