Violation reporting
How to collect script-src violations in production with Reporting-Endpoints and report-to, plus the older report-uri directive.
Violation reporting tells the browser to POST a report every time your policy
blocks something. This is how you find real violations across production traffic
instead of guessing from local testing, and it is how you safely roll out a
stricter script-src.
Report-only first
Before enforcing a new policy, ship it in report-only mode. The browser reports violations but does not block anything, so nothing breaks while you watch:
Content-Security-Policy-Report-Only:
script-src 'self' 'nonce-r4nd0m';
report-to csp-endpoint
Run report-only until the reports stop surfacing legitimate scripts, then switch
the same policy to the enforcing Content-Security-Policy header.
The modern setup: Reporting-Endpoints + report-to
Declare named endpoints with the Reporting-Endpoints header, then point the
policy at one by name with report-to:
Reporting-Endpoints: csp-endpoint="https://reports.example.com/csp"
Content-Security-Policy:
script-src 'self' 'nonce-r4nd0m';
report-to csp-endpoint
When a script is blocked, the browser sends a JSON report to that endpoint describing the violated directive, the blocked resource, and the document URL.
The older report-uri directive
report-to is not yet honored everywhere, so many sites send both:
Content-Security-Policy:
script-src 'self' 'nonce-r4nd0m';
report-uri https://reports.example.com/csp;
report-to csp-endpoint
report-uri is deprecated but still widely supported. Sending both covers
browsers that only understand one of them. Where both are present and supported,
report-to wins.
What a report contains
A script-src report identifies the directive that was violated, the document
that triggered it, and the blocked script's URL or an inline marker. Add
'report-sample' to the directive to include a short
snippet of the offending code, which makes inline violations much easier to
track down.
Collecting reports
You need an endpoint that accepts the browser's POST, parses it, and lets you group and search violations. You can run your own, or use a hosted reporting service so you skip the parsing, storage, and noise-filtering. CentralCSP provides a reporting endpoint for CSP violations if you would rather not build that side yourself.
Whichever you choose, the reporting endpoint is what turns a blocked script from an invisible failure into something you can measure and fix.