CSP Report Endpoint
A Content-Security-Policy without a report endpoint is silent. It breaks things in your visitors' browsers and never tells you. Point report-uri at a collector, and find out before you enforce.
Why a crawl is not enough
A scanner sees what a scanner can reach: public pages, logged out, once. Real traffic includes the page behind the login, the checkout step, the A/B variant, the legacy widget on one forgotten URL, and whatever a marketing tag loaded this morning. Those are exactly the places a policy written from a crawl turns out to be too strict.
Browsers already know. Every time a policy blocks something, the browser is willing to post a short JSON report saying what and where. It just needs somewhere to send it.
How it works
- 1
Add your domain
A free account, then one monitor per site. Each gets its own secret collector URL — a long random token in the path, visible only to you.
- 2
Point your policy at it
Append report-uri to the policy you already serve, and add a Reporting-Endpoints header with report-to so newer browsers report too. Browsers that understand report-to ignore report-uri, so listing both covers everyone.
- 3
Ship it in Report-Only mode
Send the strict policy under Content-Security-Policy-Report-Only. Nothing is blocked. The browser tells you what it would have blocked, in visitors’ real sessions, on the pages a crawler never sees.
- 4
Read what came back, and act
Reports are folded to one row per day, directive and blocked origin, each with what it means and the fixes in order. When the only thing left is extension noise, rename the header and start enforcing.
What you add to your site
Two headers. Your collector URL replaces the token below; you get the real one when you create the monitor.
Content-Security-Policy-Report-Only: default-src 'self'; object-src 'none'; base-uri 'self'; report-uri https://intodns.ai/api/csp-report/u/<your-token>; report-to csp-endpoint Reporting-Endpoints: csp-endpoint="https://intodns.ai/api/csp-report/u/<your-token>"
Keep it on the Report-Only header name until the reports are quiet. Under that name a policy cannot break anything, which is the whole point of starting there.
What comes back
Browsers send one report per blocked resource per page view, so a busy site produces tens of thousands a day that say the same four things. They arrive here folded to one row per day, directive and origin, each carrying what to do about it.
| Directive | Blocked origin | Count | What to do |
|---|---|---|---|
script-src | inline | 8,891 | criticalMove the code into a .js file Nearly every XSS lands as inline script, so a policy that allows it stops almost nothing. No button here adds ’unsafe-inline’ to a script directive — that is the one fix worth refusing. |
script-src | https://cdn.jsdelivr.net | 1,204 | highHost the file yourself Recognised as the jsDelivr CDN. Allowing a third party in a script directive lets that origin run code in your pages after any future change on their side. |
img-src | data | 312 | lowAdd data: to img-src Ordinary build output — small images inlined to save a request. Rendered, not executed, so allowing it costs little. |
style-src | chrome-extension://… | 97 | lowNo action A visitor’s extension injecting into your page. Not your site, and not something to widen a directive for. |
Illustrative rows, to show the shape of the output.
Then it writes the policy
Once a representative period has passed, the monitor can synthesize a policy from what your visitors actually loaded, optionally combined with a fresh crawl. It starts locked down — default-src 'self', object-src 'none', base-uri 'self', frame-ancestors 'self' — and adds only origins that were really observed.
Origins seen once are still included, but called out for review: a single sighting is as likely to be somebody's browser extension as a real dependency. A weekly digest tells you when something new shows up, which is how you find out that a new marketing tag went live.
Get your endpoint
Free account, one monitor per domain, your own collector URL. The reports are yours — nobody else can read them.
Create a free accountAlready signed in? Go to the CSP dashboard.