# Cross-Origin-Embedder-Policy

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

Source: https://howhttpworks.com/headers/cross-origin-embedder-policy
Last reviewed: 2026-10-05

> **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](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cross-Origin-Embedder-Policy#directives).

## Syntax

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

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

Then check the result in the served page:

```javascript
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](https://developer.mozilla.org/en-US/docs/Web/API/Window/crossOriginIsolated). Trust `crossOriginIsolated`, not the header.

## Implementation

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

```nginx
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](https://nginx.org/en/docs/http/ngx_http_headers_module.html#add_header). 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:

```javascript
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](https://expressjs.com/en/5x/api/response/#res.sendFile). 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:

```html
<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](https://www.w3.org/TR/css-fonts-4/#font-fetching-requirements), 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:

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

The [report-only header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cross-Origin-Embedder-Policy-Report-Only) 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](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/IFrame_credentialless) 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.

## Related Headers

- [Cross-Origin-Opener-Policy](https://howhttpworks.com/headers/cross-origin-opener-policy)
- [Cross-Origin-Resource-Policy](https://howhttpworks.com/headers/cross-origin-resource-policy)
- [Access-Control-Allow-Origin](https://howhttpworks.com/headers/access-control-allow-origin)
