CSP reporting for developers
Tighten your CSP without
breaking the site.
Most sites ship a policy that allows everything it was supposed to restrict, because nobody can list every resource their site loads. We watch your real traffic for a week and assemble the tight header from what actually showed up.
default-src 'self'; script-src 'self' 'unsafe-inline' https:; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; no report-uri
default-src 'self'; script-src https://example.com 'nonce-{per request}' https://www.googletagmanager.com; style-src 'self' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; frame-src https://js.stripe.com; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; report-uri https://ingest.csplog.io/…
One URL to get there. Seven days of watching. No outage on the way.
Four steps. The same four you see inside the app.
How it worksEach of these steps used to be a project of its own. Now each one checks itself against your live site, and nothing waits for you to press a button.
Step 1 of 4
Deploy the watching header
A deny-all header in Report-Only mode. It blocks nothing. It makes every resource on every page report itself, including the ones your own code loads. Keep your current header next to it.
We read the header back from your site and tick the step when it is right.
Content-Security-Policy-Report-Only: default-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'; report-uri https://ingest.csplog.io/api/csp-report?token=7f3a…
Step 2 of 4
Review the origins
Reports arrive grouped by origin, not by URL. Extensions, antivirus and bots are dropped before they reach you. Known services are named.
You decide each origin once. Unknown ones get an identification from Triage AI. It never decides for you.
| Origin · directive | Events · recent | What | Decision |
|---|---|---|---|
| font-srcfonts.gstatic.com | 12,480 | Fonts | Allow |
| script-srcwww.googletagmanager.com | 8,912 | Analytics | Allow |
| frame-srcjs.stripe.com | 1,102 | Payment | Allow |
| img-srcpx.ads.example.net | 640 | Advertising | Ignore |
| script-srccdn.unknown-widget.io | 318 | Unknown conf 64 | — |
Browser-extension and antivirus noise is filtered before it reaches this table.
Step 3 of 4
Handle inline code
Inline scripts and styles have no origin to allow. The app finds each one in the reports and offers a path for it: a nonce, a hash, or moving it to a file.
For scripts, 'unsafe-inline' is never suggested and never the default. It goes into the policy only when you accept it explicitly, and the policy is then graded Basic.
<script>window.dataLayer = window.dataLayer || [];</script> → hash, one line in the policy: script-src 'sha256-Qw3fL9v0kR2m…8Kc=' <script nonce="…">trackConsent();</script> → nonce, rotated per request, checked on the live page
Step 4 of 4
Implement the policy
You get an Implementation brief. It carries the committed header byte for byte, the inline mechanism, the site fixes, and the origins you blocked on purpose. Written as requirements, not recipes. We do not know your framework or your deploy. Your coding agent does.
Hand it to Claude Code, Codex, or a colleague. It changes code and stops. You review the diff and ship. We read the live header back and tick the step.
# Implementation brief · example.com Serve this header on every HTML response. Report-Only first. Content-Security-Policy-Report-Only: default-src 'self'; script-src https://example.com 'nonce-{per request}' https://www.googletagmanager.com; … Rules - The header above is the target. Do not add sources. - These origins are blocked on purpose: cdn.unknown-widget.io - Change code only. Do not deploy, release or restart.
From €9 a month.
PricingThe violation ceilings are abuse bounds, not usage targets. They exist so a runaway script cannot run up a bill. Filtered noise never counts.
| Trial€0 14 days | Starter · recommended€9 / $10 per month | Professional€49 / $55 per month | |
|---|---|---|---|
| Projects | 1 | 1 | 10 |
| Violations / month, per account | 100,000 | 1,000,000 | 10,000,000 |
| Retention | 30 days | 30 days | 90 days |
| Drift alerts + weekly summary | yes | yes | yes |
| Implementation brief | yes | yes | yes |
| MCP access | no | no | yes |
| Card required | no | yes | yes |
| Get notified | Get notified | Get notified |
One trial per domain. EU customers pay in euros, everyone else in dollars. Prices include VAT and sales tax. Upgrades are immediate and prorated. Downgrades apply at the end of the billing period. Cancel anytime.
Check a site before you sign up.
A check of the headers a public URL serves right now. A grade you can share. No account.
- highscript-src allows 'unsafe-inline'
- mediumNo violation reporting configured
- lowobject-src is not 'none'
- lowNo base-uri directive