Cross-Origin-Embedder-Policy-Report-Only

Enforcing a strict Cross-Origin-Embedder-Policy risks breaking third-party resources. The HTTP Cross-Origin-Embedder-Policy-Report-Only response header tests a COEP policy in observation mode, sending violation reports to a designated endpoint instead of blocking cross-origin resource loads.

Usage

A strict Cross-Origin-Embedder-Policy controls how a page loads cross-origin resources. Setting require-corp on the enforcing header blocks any cross-origin resource lacking an explicit Cross-Origin-Resource-Policy grant or CORS header. This breaks images, scripts, and iframes served from third-party origins not configured for cross-origin embedding.

The Cross-Origin-Embedder-Policy-Report-Only header applies the same policy logic in observation mode. The browser evaluates every cross-origin resource load against the declared policy and generates a report for each violation, but still loads the resource normally. Reports are sent to the endpoint named in the report-to directive, which maps to a URL declared in the Reporting-Endpoints or Report-To header.

This report-only approach allows operators to measure the impact of a COEP policy before committing to enforcement. Once the violation reports confirm no unexpected breakages remain, the policy moves to the enforcing Cross-Origin-Embedder-Policy header. Combined with Cross-Origin-Opener-Policy, a fully enforced COEP enables crossOriginIsolated status for access to SharedArrayBuffer and high-resolution timers.

Directives

unsafe-none

The unsafe-none directive is the default behavior. No cross-origin embedding restrictions are applied, and no violation reports are generated. This is the baseline before any COEP policy is introduced.

require-corp

The require-corp directive reports violations when a cross-origin resource is loaded without an explicit Cross-Origin-Resource-Policy header or CORS grant. Every embedded image, script, stylesheet, iframe, or fetch from a different origin generates a violation report unless the resource explicitly opts in to sharing.

credentialless

The credentialless directive reports violations for cross-origin requests sent with credentials (cookies, client certificates) to origins not granting CORS access. Unlike require-corp, resources loaded without credentials pass through without generating a report. This is a less restrictive alternative to require-corp for sites with many third-party embeds.

report-to

The report-to directive specifies the name of the reporting endpoint group receiving COEP violation reports. The name maps to an endpoint declared in the Reporting-Endpoints or Report-To response header. Without this directive, violations are observed but no reports are sent.

Example

An unsafe-none policy in report-only mode with a report-to directive monitors the current state before tightening the policy. The browser generates no reports because unsafe-none matches the default behavior. Sites use this configuration to verify the reporting pipeline works before switching to a stricter value.

Cross-Origin-Embedder-Policy-Report-Only: unsafe-none; report-to="default"
Reporting-Endpoints: default="https://reports.example.re/default"

A require-corp policy in report-only mode sends violation reports to an endpoint named coep_report. The browser flags every cross-origin resource lacking a Cross-Origin-Resource-Policy or CORS grant, reporting each violation without blocking the load.

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

A credentialless policy in report-only mode reports violations only for credentialed cross-origin requests missing CORS access. Resources loaded without credentials pass through cleanly.

Cross-Origin-Embedder-Policy-Report-Only: credentialless; report-to="default"
Reporting-Endpoints: default="https://reports.example.re/default"

What the reports catch, and what they miss

Reporting requires wiring. The report-to parameter names an endpoint declared in Reporting-Endpoints, and without the parameter the header is inert, observing nothing. The older Report-To JSON header is deprecated, and Safari never shipped support.

Reports arrive batched as JSON with Content-Type: application/reports+json. The body carries type (corp, navigation, or worker initialization), blockedURL, destination, and disposition: "reporting". The field is blockedURL in camel case, and older guides showing blocked-url predate the final specification.

Three coverage gaps decide how much trust a quiet report stream deserves.

Reports fire for resources lacking a CORP header, and stay silent for resources actively refusing with same-origin or same-site. Those load attempts are blocked already and remain blocked after enforcement, without ever appearing in a report. A clean report-only run is therefore evidence, not proof.

Delivery is effectively Chromium-only. Firefox and Safari send no COEP violation reports, so a rollout measured through reports observes Chrome users alone, and breakage limited to other engines surfaces only at enforcement.

Duplication fails open. Two copies of the header, one from the origin and one from a proxy, merge into a value parsing as unsafe-none, which disables the policy silently. The same applies to the enforcing header.

Report-only grants no isolation

The header observes and changes nothing, so crossOriginIsolated stays false and SharedArrayBuffer stays unavailable until the enforcing COEP ships. One pairing softens the ordering problem: report-only COOP takes report-only COEP into account, so shipping both report-only headers together produces meaningful COOP reports before either is enforced.

One workable staged path starts with report-only COOP, adds report-only COEP, fixes each reported resource with the matching CORP value or a CORS fetch, then enforces both, verified by self.crossOriginIsolated returning true. The specification leaves the deployment order free.

See also

Last updated: August 17, 2026