Report-Only
The Content-Security-Policy-Report-Only header reports what a policy would block without enforcing it, for safe CSP rollout.
Last update:
The Content-Security-Policy-Report-Only header tells the browser to check a
Content Security Policy (CSP) and report every violation, without blocking
anything. You see exactly what a policy would break before it breaks it. That
makes it the safe way to roll out or tighten a policy on a live site.
A candidate policy under test, paired with the endpoint that receives its reports:
Reporting-Endpoints: csp-endpoint="https://<Endpoint-ID>.report.centralcsp.com"Content-Security-Policy-Report-Only: default-src 'self'; report-to csp-endpointQuick overview
A Report-Only policy is written exactly like an enforced one. The only difference
is the header name and the resulting disposition. With
Content-Security-Policy-Report-Only the disposition is report, so the browser
loads the resource and sends a CSP violation report
instead of applying the Content-Security-Policy
header's enforce behavior.
Content-Security-Policy-Report-Only:
default-src 'self';
script-src 'self' 'nonce-r4nd0m';
object-src 'none';
base-uri 'none';
report-to csp-endpointA report-only policy is useful only if it has somewhere to send reports. Pair it
with a report-to
directive (and the legacy report-uri
only if you need to cover old browser versions) so the violations reach an
endpoint you control.
Values
The header value is a CSP, the same semicolon-separated list of directives you would put in an enforced policy. Every CSP directive is valid here. The directives that actually matter in Report-Only are the reporting ones, since nothing is enforced.
| Part | Status | What it does |
|---|---|---|
| The directive list | ✅ Good | Defines the policy the browser evaluates against the page. |
report-to | ✅ Good | Names the endpoint group that receives violation reports. |
report-uri | ⚠️ Deprecated | Legacy reporting target, kept only for old, unupdated browser versions. |
A response can carry both headers at once. Send an enforced
Content-Security-Policy for the policy you trust today, and a separate
Content-Security-Policy-Report-Only for the stricter policy you are testing. The
browser evaluates each independently and reports the report-only one without
touching the page.
Insecure values to avoid
A Report-Only policy never protects anything, so it has no insecure values of its
own. The mistake is treating it as protection. Shipping only
Content-Security-Policy-Report-Only in production means the browser reports
attacks but blocks none of them. An attacker's inline script still runs. Use
Report-Only to learn what to enforce, then move the validated policy to the
enforcing Content-Security-Policy header.
A second mistake is a report-only policy with no reporting directive at all. With
no report-to or report-uri, the browser evaluates the policy and discards
every violation, so you learn nothing.
Why this header exists
A real policy almost always breaks something on the first try: an inline script,
a third-party widget, a data: image. Enforcing an untested policy takes the site
down. Report-Only was introduced so you can deploy a candidate policy, watch the
violations roll in from real traffic, fix the gaps, and only then enforce it. It
turns CSP rollout from a guess into a measurement.
What it protects against
The header itself blocks nothing, so it protects nothing directly. Its security
value is indirect. It lets you reach a strict, enforced
Content-Security-Policy
safely. The faster you can validate a tight policy, the sooner you get real
protection against cross-site scripting (XSS) and injection. Collecting the
report-only violations in CentralCSP shows you exactly which
directives to adjust before you flip to enforcement.
Known bypasses and limitations
A <meta http-equiv> tag cannot deliver a Report-Only policy. The meta element
only supports the enforcing Content-Security-Policy, so Report-Only is an HTTP
response header exclusively. The same applies to the reporting directives
(report-to, report-uri), which a meta tag also cannot set.
Report-Only violations are reported per policy, so a noisy candidate policy can generate a large volume of reports on a high-traffic page. Sample and triage them rather than reading raw JSON.
Risks of misconfiguration
The dominant risk is confusing the two headers. Leaving a strict policy in
Report-Only forever gives a false sense of security with zero enforcement, while
promoting an untested policy straight to Content-Security-Policy breaks the
page. Validate in Report-Only, then enforce.
Recommendation
Whenever you tighten a policy, run the candidate in Report-Only alongside the
enforced one, and point both at report-to with a
Reporting-Endpoints
declaration.
Reporting-Endpoints: csp-endpoint="https://<Endpoint-ID>.report.centralcsp.com"Content-Security-Policy-Report-Only:
script-src 'nonce-r4nd0m' 'strict-dynamic';
object-src 'none';
base-uri 'none';
report-to csp-endpointEvery current engine delivers report-to reports now, so this pair is the
primary transport; add report-uri only for old-version tails. Staged rollout
through Report-Only is the approach the
web.dev strict CSP guide recommends.
How to set it up
- Send
Content-Security-Policy-Report-Onlywith your candidate policy and areport-todirective that names an endpoint group. - Declare that group with the
Reporting-Endpointsheader so the browser knows where to send reports.
Reporting-Endpoints: csp-endpoint="https://<Endpoint-ID>.report.centralcsp.com"Content-Security-Policy-Report-Only:
default-src 'self';
script-src 'self' 'nonce-r4nd0m';
object-src 'none';
base-uri 'none';
report-to csp-endpoint- Watch the CSP violation reports,
fix the legitimate breakages, and once the policy is clean, move it to the
enforcing
Content-Security-Policyheader. The Reporting API configuration checker confirms your endpoint wiring works before you rely on the reports.
Browser support
Widely supported. Content-Security-Policy-Report-Only works across modern
browsers. The report-to plus
Reporting-Endpoints
transport is now cross-browser too, supported in current Chrome, Safari, and
Firefox (Firefox was the last engine to add it). Keep report-uri only to cover
old, unupdated browser versions.
See also
- Content-Security-Policy
- report-to directive
- report-uri directive
- Reporting-Endpoints header
- CSP violation report
- CSP enforce vs report-only
- report-uri vs report-to
Sources
Headers
The HTTP headers that deliver a Content Security Policy, enforce vs report-only, report-to vs report-uri, meta delivery limits, and how policies combine.
Keywords
Reference for CSP keyword sources, self, none, unsafe-inline, unsafe-eval, strict-dynamic, unsafe-hashes, report-sample, and what each one allows.