How HTTP Works

Response header

< Cross-Origin-Embedder-Policy: require-corp

Cross-Origin-Embedder-Policy

Learn how Cross-Origin-Embedder-Policy (COEP) controls cross-origin resource loading. Required for SharedArrayBuffer and high-resolution timer access.

Reviewed 3 min readadvanced2 sourcesTry itMarkdown
Direction
Response
Category
Security
Spec
HTML Standard
On this page

TL;DR: Send Cross-Origin-Embedder-Policy: require-corp together with Cross-Origin-Opener-Policy: same-origin on your HTML to make the page cross-origin isolated, which unlocks SharedArrayBuffer and precise timers. The catch: every cross-origin no-cors asset then needs a Cross-Origin-Resource-Policy header, and CORS-mode assets must pass CORS. credentialless is the easier option, because it loads no-cors assets without credentials instead of demanding CORP.

What is Cross-Origin-Embedder-Policy?

COEP is a policy on a document’s response that controls which cross-origin content that document may load. It can’t grant permission on a CDN’s behalf, and it doesn’t turn an ordinary no-cors image request into a CORS request. Whether an asset loads comes down to the asset’s request mode and its own response headers. MDN lays out the rules for each mode.

Syntax

Cross-Origin-Embedder-Policy: require-corp

Put it on the HTML response. Adding it only to API responses or asset files has no effect on the page.

Value Guide

  • unsafe-none is the default and adds no COEP restriction. Ordinary CORS and CORP rules still apply.
  • require-corp lets a cross-origin no-cors asset load only if it sends a suitable CORP header; CORS-mode loads must succeed under CORS.
  • credentialless lets cross-origin no-cors loads through without CORP by sending them without credentials and ignoring any cookies in the response. CORS-mode requests still need CORS permission, and an asset that sends a restrictive CORP is still blocked.

Example

The headers on the document response (headers on this page are trimmed examples):

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

Then check the result in the served page:

console.log(window.isSecureContext, window.crossOriginIsolated)

Isolation also requires a secure context and a cross-origin-isolated permissions policy that allows it. MDN documents the capability check. Trust crossOriginIsolated, not the header.

Implementation

In nginx, add these to the server or location that serves the document:

add_header Cross-Origin-Opener-Policy "same-origin" always;
add_header Cross-Origin-Embedder-Policy "require-corp" always;

The always parameter adds the headers to error responses too. Watch for nested locations with their own add_header directives, because those replace the inherited ones.

In an existing Express app, register middleware for the document before the route that serves the HTML:

app.use('/isolated', (_req, res, next) => {
  res.set({
    'Cross-Origin-Opener-Policy': 'same-origin',
    'Cross-Origin-Embedder-Policy': 'require-corp'
  })
  next()
})
app.get('/isolated', (_req, res) => {
  res.sendFile('isolated.html', { root: '/srv/app/public' })
})

The route expects /srv/app/public/isolated.html to exist. Express covers header middleware and rooted file responses. Scope these headers to pages that need isolation, then test their resources and popup flows.

Why Pages Break After Enabling COEP

A plain cross-origin image loads in no-cors mode. Under require-corp, you have two fixes: the provider returns Cross-Origin-Resource-Policy: cross-origin, or you request the image in CORS mode:

<img src="https://cdn.example.com/logo.png" crossorigin="anonymous" alt="Logo">

The CORS route needs the CDN to answer this anonymous request with a matching Access-Control-Allow-Origin or *. That header alone won’t help while your page still makes a no-cors request. Fonts are always loaded with CORS, so a font that fails its CORS check stays broken no matter what CORP header you add.

Rollout Strategy

Start in report-only mode to find violations without enforcing anything. Assuming you run the report endpoint:

Reporting-Endpoints: coep="https://reports.example.com/coep"
Cross-Origin-Embedder-Policy-Report-Only: require-corp; report-to="coep"

The report-only header only reports; it doesn’t isolate the page. Report delivery varies by browser, so also test the real page with DevTools open.

Enabling COEP Without Breaking Your Page

Audit request modes before you touch asset headers. A third-party script might load as no-cors, while a module script or font needs CORS. Cross-origin iframes add their own document-policy requirements, so putting CORP on the child document is only part of the fix.

COEP credentialless isn’t a general fix for third-party iframes. The separate, experimental <iframe credentialless> attribute loads the frame in an ephemeral context and relaxes the embedding rules for it. Test it in every browser you support before you rely on it.

Frequently asked questions

What is Cross-Origin-Embedder-Policy?

COEP controls cross-origin loading by request mode. With require-corp, cross-origin no-cors assets need CORP permission, while CORS-mode assets must pass CORS.

What values can COEP have?

The values are unsafe-none, require-corp, and credentialless. The default is unsafe-none; credentialless drops credentials only for cross-origin no-cors resource loads.

Why does COEP break my images?

A no-cors cross-origin image needs an appropriate CORP header under require-corp. Alternatively, add crossorigin and have the image server permit that CORS request.

How do COOP and COEP work together?

COOP same-origin with COEP require-corp or credentialless can enable cross-origin isolation in a secure context, provided permissions policy does not block the capability. Check window.crossOriginIsolated.

Sources

  1. MDN Web Docs: Cross-Origin-Embedder-Policydeveloper.mozilla.org
  2. HTML Standard: Cross-origin embedder policieshtml.spec.whatwg.org

Keep going

Browse /search