Documentation

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):

Cross-Origin-Embedder-Policy (COEP):

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-Policy headers 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:

  • SharedArrayBuffer for 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:

HTTP Define the reporting endpoint
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:

HTTP COOP Report-Only mode for safe testing
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:

HTTP COEP Report-Only mode for safe testing
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
Test both headers together: Deploy both 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-origin header to allow embedding
  • Or add Cross-Origin-Resource-Policy: same-site for same-site embedders only

For third-party resources:

  • Add crossorigin attribute to enable CORS mode: <img src="..." crossorigin>
  • Request CORP header support from the resource provider
  • Consider using credentialless COEP mode (see below)

For cross-origin popups (OAuth, payments):

  • Use same-origin-allow-popups COOP 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:

HTTP Full cross-origin isolation with reporting
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"
Keep reporting enabled: Continue using 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:

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.
Cross-origin isolation requires same-origin: To achieve cross-origin isolation and enable 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:

HTTP Using credentialless COEP
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-cors requests are sent without cookies
  • Resources don't need Cross-Origin-Resource-Policy headers
  • CORS requests still require proper Access-Control-Allow-Origin headers
  • Cross-origin isolation is still achieved (with same-origin COOP)
When to use credentialless: Use 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

JSON COOP violation (popup blocked)
{
  "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
  }
}
JSON COEP violation (resource blocked)
{
  "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 crossorigin attribute<img src="..." crossorigin> enables CORS
  • Use credentialless COEP — 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:

JavaScript Check cross-origin isolation status
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

Nginx nginx.conf
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

Ruby config/application.rb or initializer
# 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

Apache .htaccess or httpd.conf
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-origin AND COEP require-corp or credentialless
  • 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-Policycross-origin-isolated must not be blocked

Reports Not Appearing

  • Verify report-to directive — Ensure headers include report-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 credentialless COEP 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 valuesame-origin breaks popup communication; consider same-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