---
title: "COOP, COEP, CORP: cross-origin isolation guide (2026)"
description: "Complete guide to Cross-Origin-Opener-Policy, Cross-Origin-Embedder-Policy and Cross-Origin-Resource-Policy. Why YouTube, Stripe and OAuth popups stop working and how to fix them without giving up isolation."
date: 2026-04-19
category: Security
tags: ["Security", "COOP", "COEP", "CORP", "Cross-Origin", "HTTP Headers", "SharedArrayBuffer"]
url: https://uper.pl/en/blog/coop-coep-corp-cross-origin-isolation/
---

# COOP, COEP, CORP — complete guide to cross-origin isolation, SharedArrayBuffer, and common issues with YouTube, Stripe and OAuth

Three HTTP headers — **Cross-Origin-Opener-Policy (COOP)**, **Cross-Origin-Embedder-Policy (COEP)** and **Cross-Origin-Resource-Policy (CORP)** — together form a mechanism called **cross-origin isolation**. Configured correctly, they protect your site against Spectre-style attacks and tabnapping, and unlock `SharedArrayBuffer` and high-resolution timers. Configured incorrectly, they silently break YouTube embeds, Stripe Checkout, and Google Sign-In. This guide shows how to set them up right.

## TL;DR — three headers in 60 seconds

| Header | What it controls | When to set it |
|--------|------------------|----------------|
| **COOP** | Whether other windows/popups can access your `window` | Always — protects against tabnapping |
| **COEP** | Whether your page can load subresources without consent | Only if you need `SharedArrayBuffer` or `crossOriginIsolated` |
| **CORP** | Who can load your resources (images, scripts) | On resources you host for other sites |

For a typical marketing site / blog, this is enough:

```http
Cross-Origin-Opener-Policy: same-origin-allow-popups
```

For a web app that needs `SharedArrayBuffer` (multithreaded WebAssembly, FFmpeg.wasm, games, video editors):

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

## Why these headers exist

### Spectre (2018)

In January 2018 the [Spectre vulnerability](https://spectreattack.com/) was disclosed — a side-channel attack exploiting speculative execution in CPUs. It allowed reading memory from other processes, including other browser tabs. For browsers, this was catastrophic: JavaScript from an ad frame could theoretically read passwords from another tab.

The response was **Site Isolation** (Chrome) and eventually **cross-origin isolation** at the HTTP level. Pages that want access to high-resolution timers and shared memory (`SharedArrayBuffer`) must prove they are isolated from potentially hostile origins.

### Tabnapping and opener exploitation

When you open a window via `<a target="_blank">` or `window.open()`, the new window gets access to `window.opener`. Without protection, this reference lets a malicious page rewrite the parent window's content (`window.opener.location = 'phishing.com'`). This is classic **tabnapping**.

`rel="noopener"` on links solves the problem for individual links, but **COOP solves it at the whole-page level**, regardless of how the window was opened. Cross-origin headers are one of many defensive layers — incidents like the [2026 WordPress plugin supply-chain attack](/en/blog/wordpress-plugin-supply-chain-attack-2026/) show that without defense-in-depth, a single vulnerability can open the door to hundreds of thousands of sites.

## COOP — Cross-Origin-Opener-Policy

COOP decides **who has access to your `window` object**. Three valid values:

### `unsafe-none` (default)

```http
Cross-Origin-Opener-Policy: unsafe-none
```

No isolation. Any page that opens you via `window.open()` keeps its `window.opener` reference and can exploit it. **Do not use in production** — even if you never use popups, you're leaving the door open to tabnapping.

### `same-origin-allow-popups` (recommended for most sites)

```http
Cross-Origin-Opener-Policy: same-origin-allow-popups
```

- **Inbound isolation:** other-origin pages opening you lose access to your `window`.
- **Outbound isolation:** popups *you* open keep normal communication with their opener.

This is the sweet spot. You get tabnapping protection without breaking OAuth, sharing, or payment popups. **This is what we use on uper.pl.**

### `same-origin` (full isolation)

```http
Cross-Origin-Opener-Policy: same-origin
```

Full isolation in both directions. No other-origin page has access to your `window`, and vice versa. This is required to reach `crossOriginIsolated === true` and unlock `SharedArrayBuffer`.

**The cost:** popups from other origins opened from your page immediately lose `window.opener`. This is exactly what breaks YouTube, Stripe, and Google Sign-In.

### Decision table

| Site type | Recommended value |
|-----------|-------------------|
| Marketing site / blog | `same-origin-allow-popups` |
| SaaS with embeds (YouTube, Stripe, Intercom) | `same-origin-allow-popups` |
| SPA with multithreaded WebAssembly | `same-origin` |
| Video editor / in-browser game | `same-origin` |
| E-commerce with popup checkout | `same-origin-allow-popups` |

## COEP — Cross-Origin-Embedder-Policy

COEP enforces that **every resource loaded by your page** from other origins **explicitly consents** to being embedded by you. This is the second half of the `crossOriginIsolated` requirement.

### `unsafe-none` (default)

No requirements. Load anything from anywhere.

### `require-corp`

```http
Cross-Origin-Embedder-Policy: require-corp
```

Every cross-origin resource (image, script, iframe) must either:
- Have a `Cross-Origin-Resource-Policy: cross-origin` header (explicit consent), **or**
- Be loaded with CORS (`Access-Control-Allow-Origin`).

Otherwise the browser blocks it. This is strict — **it will break most CDN and third-party integrations that don't set CORP/CORS**.

### `credentialless` (newer, 2022+)

```http
Cross-Origin-Embedder-Policy: credentialless
```

A looser variant: instead of requiring CORP/CORS, the browser simply loads resources without cookies or other credentials. For most use cases (images, fonts, public APIs) this is enough, and it requires far fewer changes from third-party providers.

**Browser support:** Chrome 96+, Firefox 119+. Safari only joined in 2024 — if you support older iOS, have a fallback.

## CORP — Cross-Origin-Resource-Policy

The opposite perspective. If **you host resources** (CDN, image API, fonts for other sites), CORP tells the browser **who is allowed to load them**.

### Values

```http
Cross-Origin-Resource-Policy: same-origin      # only your domain
Cross-Origin-Resource-Policy: same-site        # your domain and subdomains
Cross-Origin-Resource-Policy: cross-origin     # any site
```

### When to use which

- **`same-origin`** — private resources (user data APIs, dashboard images).
- **`same-site`** — resources shared across subdomains (logo on `app.example.com` and `www.example.com`).
- **`cross-origin`** — public resources that you *want* others to embed (images for embeds, public fonts, avatar CDN).

If you're an API provider and your customers complain that their COEP-enabled sites stopped loading your images — you're missing `Cross-Origin-Resource-Policy: cross-origin`.

## The magic flag: self.crossOriginIsolated

When you set both:

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

you get in JavaScript:

```js
self.crossOriginIsolated === true
```

What this unlocks:

- **`SharedArrayBuffer`** — shared memory across threads (Web Workers). Essential for multithreaded WebAssembly, FFmpeg.wasm, Three.js with Web Workers, emulators. Note: full isolation can degrade [LCP](/en/blog/lcp-optimization-guide/) because third-party resources need additional CORP/CORS headers and get blocked without them — which slows down first render in practice.
- **`performance.measureUserAgentSpecificMemory()`** — precise memory usage measurement.
- **High-resolution timers** — `performance.now()` without intentional coarsening (a Spectre mitigation).
- **`Atomics.wait()`** on the main thread.

For a typical marketing site, none of this matters. For a WebAssembly application, it's critical.

## Real-world problems and fixes

### YouTube embed stopped working

**Symptom:** the video renders, but clicking "Share", sign-in, or fullscreen (in some browsers) doesn't work.

**Cause:** you set `Cross-Origin-Opener-Policy: same-origin`. The YouTube player opens popups that immediately lose their opener reference.

**Fix:** switch to `same-origin-allow-popups`. If you need `crossOriginIsolated` (e.g. for WASM), move YouTube to a separate page without isolation.

### Stripe Checkout popup doesn't close after payment

**Symptom:** the user pays, the popup stays open, your site doesn't know the transaction succeeded.

**Cause:** Stripe calls `window.opener.postMessage()` to your site after completion. With `COOP: same-origin`, the reference is `null`.

**Fix:** `same-origin-allow-popups`, or use [Stripe Elements](https://stripe.com/docs/payments/elements) instead of Checkout (renders inside your iframe, not a popup).

### Google Sign-In / OAuth callback doesn't arrive

**Symptom:** the user signs in in the Google popup, the popup closes, but your app never receives the token.

**Cause:** same as Stripe — `postMessage` from the popup hits a `null` opener.

**Fix:** `same-origin-allow-popups`. Alternatively — use Google Identity Services (GIS) with FedCM, which uses a dedicated API instead of popups.

### CDN images stop loading after enabling COEP

**Symptom:** after adding `COEP: require-corp`, all images from your external CDN (Cloudinary, imgix, Gravatar) fail to load.

**Cause:** the CDN doesn't return a `Cross-Origin-Resource-Policy: cross-origin` header.

**Fixes:**
1. Configure the CDN to add `Cross-Origin-Resource-Policy: cross-origin` to responses (most have this option).
2. Load images with `crossorigin="anonymous"` and ensure the CDN returns `Access-Control-Allow-Origin: *`.
3. Use the looser `COEP: credentialless` instead of `require-corp`.

### Social sharing popup (Twitter/LinkedIn) behaves erratically

**Symptom:** the "Share on Twitter" popup opens, but interactions inside it are weird or crash.

**Cause:** `COOP: same-origin` on your site.

**Fix:** `same-origin-allow-popups`.

## How to debug

### 1. Check isolation status

In the DevTools console:

```js
self.crossOriginIsolated
// true  = you have full isolation
// false = you don't
```

### 2. DevTools → Application → Frames

Chrome DevTools → **Application** tab → **Frames** section → click your page. You'll see:

- `Cross-Origin Isolated: yes/no`
- Exact COOP, COEP, CORP values
- List of sub-frames and their isolation status

### 3. Violation reports

You can collect COOP violation reports:

```http
Cross-Origin-Opener-Policy: same-origin; report-to="coop-endpoint"
Reporting-Endpoints: coop-endpoint="https://yourdomain.com/coop-report"
```

You'll receive JSON describing which frame tried to do something and got blocked. Essential when debugging silent failures.

### 4. Browser console

COEP blocks show up in the console as:

```
A resource is blocked by OpaqueResponseBlocking, please check browser console for details.

Failed to load resource: net::ERR_BLOCKED_BY_RESPONSE.NotSameOriginAfterDefaultedToSameOriginByCoep
```

## Ready-made configurations

### Marketing site / blog (recommended)

```http
Cross-Origin-Opener-Policy: same-origin-allow-popups
Cross-Origin-Resource-Policy: same-site
```

No COEP. Protects against tabnapping, doesn't break any integrations.

### E-commerce with external checkout

```http
Cross-Origin-Opener-Policy: same-origin-allow-popups
Cross-Origin-Resource-Policy: same-site
```

Identical. The key point — *do not* use `same-origin`, because it will kill Stripe/PayPal popups.

### SPA with WebAssembly (SharedArrayBuffer)

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

Plus: every external resource (CDN, fonts, images) must have `Cross-Origin-Resource-Policy: cross-origin` or CORS.

### Public API / CDN provider

```http
Cross-Origin-Resource-Policy: cross-origin
```

That's it. You're telling the world: "feel free to use me, even from isolated pages".

## Interaction with other headers

- **CSP** — orthogonal. CSP controls what you load, COOP/COEP control isolation terms. [See the CSP guide for Google services](/en/blog/csp-google-services/).
- **X-Frame-Options** — about whether *you* can be embedded in an iframe. A different category than COOP.
- **Referrer-Policy** — unrelated.
- **HSTS** — unrelated. See [the complete HTTP security headers guide](/en/blog/http-security-headers/).

<FaqBlog
  questions={[
    {
      question: 'What does same-origin-allow-popups mean in Cross-Origin-Opener-Policy?',
      answer: 'It\'s a <code>COOP</code> value that isolates your page from <strong>inbound</strong> windows from other origins (tabnapping protection), but lets popups <em>you</em> open keep communication with your page. This is the best value for most marketing sites and apps using third-party integrations (YouTube, Stripe, Google Sign-In).'
    },
    {
      question: 'Why did my YouTube embed stop working after enabling COOP?',
      answer: 'You probably set <code>Cross-Origin-Opener-Policy: same-origin</code> (full isolation). The YouTube player opens popups (Share, sign-in, fullscreen) that under full isolation lose their reference to your page, so communication between them fails. Switch to <code>same-origin-allow-popups</code> — you keep tabnapping protection and YouTube works again.'
    },
    {
      question: 'How do I enable SharedArrayBuffer in the browser?',
      answer: 'You need to reach <code>crossOriginIsolated === true</code>. This requires setting two HTTP headers simultaneously: <code>Cross-Origin-Opener-Policy: same-origin</code> and <code>Cross-Origin-Embedder-Policy: require-corp</code>. Additionally, every cross-origin resource you load (images, scripts, fonts) must have a <code>Cross-Origin-Resource-Policy: cross-origin</code> header or be loaded with CORS.'
    },
    {
      question: 'What is the difference between COOP, COEP and CORP?',
      answer: '<strong>COOP</strong> (Cross-Origin-Opener-Policy) protects your <code>window</code> from other pages — it governs tab and popup isolation. <strong>COEP</strong> (Cross-Origin-Embedder-Policy) enforces that resources <em>you load</em> from other origins explicitly consent. <strong>CORP</strong> (Cross-Origin-Resource-Policy) is the inverse of COEP — you send it on resources <em>you host</em> to tell the browser who is allowed to load them.'
    },
    {
      question: 'Does a regular blog site need COEP and CORP?',
      answer: 'No. For a typical marketing site, blog, or shop, <code>Cross-Origin-Opener-Policy: same-origin-allow-popups</code> is enough. COEP and CORP are only needed when your app uses <code>SharedArrayBuffer</code>, multithreaded WebAssembly, or you host public resources for other sites.'
    },
    {
      question: 'What should I do when my image CDN breaks after enabling COEP?',
      answer: 'Three options: (1) configure the CDN to add <code>Cross-Origin-Resource-Policy: cross-origin</code> to responses — most CDNs support this; (2) load images with <code>crossorigin="anonymous"</code> and ensure the CDN returns <code>Access-Control-Allow-Origin: *</code>; (3) use the looser <code>Cross-Origin-Embedder-Policy: credentialless</code> instead of <code>require-corp</code> — it doesn\'t require changes from third-party providers.'
    },
    {
      question: 'Does setting COOP break Google Analytics or Google Tag Manager?',
      answer: 'No. GA4 and GTM communicate via fetch/XHR, not popups, so no COOP value will break them. Problems only appear with interactions that open new windows: Google Sign-In, Stripe Checkout, social sharing. See also <a href="/en/blog/csp-google-services/">the CSP guide for Google services</a>.'
    },
    {
      question: 'What is credentialless in Cross-Origin-Embedder-Policy?',
      answer: 'It\'s a newer, looser COEP value (Chrome 96+, Firefox 119+, Safari 2024+). Instead of requiring external resources to explicitly consent via CORP or CORS, the browser simply loads them <em>without cookies or other credentials</em>. For public resources (images, fonts, public APIs) this is enough, and it requires far fewer changes from third-party providers.'
    }
  ]}
  heading="Frequently asked questions about COOP, COEP and CORP"
  id="faq"
/>

## Check your cross-origin isolation with UPER SEO Auditor

Diagnosing silent COOP/COEP failures is painful — the symptoms are weird popup behavior and broken OAuth, not clean error messages. The **Security tab in [UPER SEO Auditor](https://chromewebstore.google.com/detail/uper-seo-auditor/khhpbeckpphaoiemjdijhbfpjnendage)** (Chrome extension) shows all three headers for the current page:

- **Cross-Origin-Opener-Policy** — current value and whether it matches a sensible default
- **Cross-Origin-Embedder-Policy** — detected or missing, including `credentialless` support
- **Cross-Origin-Resource-Policy** — for resources served by the page itself

All three feed into a weighted 0-10 security score alongside HSTS, CSP, X-Frame-Options, Referrer-Policy and Permissions-Policy. Install it, open the Security tab, and you'll see your real production headers without touching the terminal.

## Summary

For 95% of sites, the only header from this trio you need is:

```http
Cross-Origin-Opener-Policy: same-origin-allow-popups
```

It protects against tabnapping and doesn't break anything. COEP and CORP are only needed if you host resources for others or your app uses `SharedArrayBuffer`.

If you already deployed full isolation (`same-origin` + `require-corp`) and suddenly notice silent popup failures — switch back to `same-origin-allow-popups`. The security cost is minimal, the functionality cost is huge.

## Sources

- [MDN — Cross-Origin-Opener-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy)
- [MDN — Cross-Origin-Embedder-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy)
- [MDN — Cross-Origin-Resource-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy)
- [web.dev — Cross-Origin Isolation](https://web.dev/articles/cross-origin-isolation-guide)
- [Chrome Platform — COEP: credentialless](https://developer.chrome.com/blog/coep-credentialless-origin-trial/)
- [Spectre Attack — whitepaper](https://spectreattack.com/)
