Learn · Deployment

Report-Only vs. enforcement

The CSP rollout pattern that lets you ship a strict policy without breaking production: collect evidence, refine the allowlist, then switch from observe to enforce.

Why Report-Only exists

A Content Security Policy controls the browser's loading behavior, and the browser is unforgiving: an unallowed script just doesn't run. If your draft policy missed a vendor your checkout depends on, an enforced rollout silently breaks payments.

Report-Only is the spec's answer. The browser evaluates the policy and emits a structured report for every would-be violation — without blocking the load. You get the same visibility an enforced policy would give you, with none of the risk.

Reference: W3C Content Security Policy Level 3

Three headers, three roles

The two header names are spelled out below; the third row is the pattern of running them together during a transition.

  • Observability

    Content-Security-Policy-Report-Only

    The browser parses and evaluates the policy. Subresources that would have been blocked are still loaded — and a violation report is sent. Use this to assess impact before any user-facing impact.

  • Enforcement

    Content-Security-Policy

    The browser evaluates and blocks. If a report-to or report-uri endpoint is configured, violations are still reported — so you keep visibility while protection is on.

  • Iteration

    Both at once

    Send both headers simultaneously: enforce a known-safe baseline policy and Report-Only a stricter candidate. When the stricter one is quiet, promote it.

The rollout pattern

Six steps from first scan to a maintained, enforced policy.

  1. 1

    Draft from observed behavior

    Don't write a CSP from a wishlist. Run a browser-rendered crawl, see the actual scripts, styles, fonts, frames, and connect targets your pages load, and assemble the policy from that evidence.

  2. 2

    Deploy in Report-Only mode

    Ship the draft policy under the Content-Security-Policy-Report-Only header. The browser evaluates every directive but does not block — it only emits violation reports.

  3. 3

    Collect violations from real traffic

    Crawls miss what's behind login walls, payment forms, and personalization. Real user sessions surface the third parties and inline blocks the scanner couldn't reach.

  4. 4

    Refine the allowlist

    For every recurring violation, decide: is this an allowed source we missed (add it), an unwanted vendor (remove it from the site), or noise (ignore the path or set tighter rules).

  5. 5

    Promote to enforcement

    When violations stabilize at zero (or only known intentional ones), swap the header from Content-Security-Policy-Report-Only to Content-Security-Policy. The browser starts blocking.

  6. 6

    Keep monitoring

    Vendors update tags, marketing adds pixels, engineers add SDKs. Even after enforcement, alerting on new violations is how you catch drift before it becomes an incident.

Headers side by side

During the transition, send both. The Report-Only header carries the stricter candidate; the enforcement header keeps a known-safe baseline live.

# Currently enforced (known safe)
Content-Security-Policy:
  default-src 'self';
  script-src 'self' https://cdn.example.com;
  report-to csp-endpoint;

# Candidate strict policy under evaluation
Content-Security-Policy-Report-Only:
  default-src 'none';
  script-src 'nonce-{RANDOM}' 'strict-dynamic';
  base-uri 'none';
  object-src 'none';
  report-to csp-endpoint-strict;

When the strict policy reports zero unexpected violations across the traffic patterns you care about, swap headers — the enforcement policy becomes the strict one, and you can either retire Report-Only or use it for the next iteration.

Common pitfalls

  • Skipping Report-Only entirely. Going straight to enforcement on a real production site almost always breaks something — even if just a tag manager or a new vendor someone shipped last sprint.

  • Treating zero violations as 'done' too quickly. Crawls and Report-Only over a single weekend won't reveal seasonal flows, mobile-only paths, or low-traffic admin tools.

  • Ignoring report-to once enforcing. Violations after enforcement are how you discover vendor changes, supply-chain swaps, and accidental insecure code.

  • Including 'unsafe-inline' to avoid violations. That stays in production forever. Use a nonce or hash instead, even if it means a bit more wiring.

14-day Pro trial

Try Consepo Pro free for 14 days

Real-time violation monitoring, multi-platform exports, team collaboration, and unlimited scans. No credit card required to start.