Skip to content

Content Security Policy

What a CSP blocks, how to recognise it in the browser console, and the exact directives the tracking script needs.

If your site sends a Content-Security-Policy header, the browser will refuse to load or contact anything the policy does not list. This is one of the few failures that does announce itself: the browser writes the error, even though the script itself never logs.

What you see

Two messages, depending on which half is blocked.

text
Refused to load the script 'https://statsy.co/js/script.js' because it violates
the following Content Security Policy directive: "script-src 'self'".

Refused to connect to 'https://statsy.co/api/collect' because it violates
the following Content Security Policy directive: "connect-src 'self'".

The first means no data at all. The second means the script runs but every beacon is dropped before it leaves the browser, which looks exactly like no data arriving.

What to allow

Two directives, both pointing at the same origin.

text
Content-Security-Policy:
  script-src 'self' https://statsy.co;
  connect-src 'self' https://statsy.co;

If you serve the script from your own hostname, use that hostname in both directives instead. See Serving the script from your own domain.

Note. The tracker loads no images, fonts or stylesheets, so img-src, font-src and style-src need no changes for it.

Replays, heatmaps and performance need script-src too

When you turn on session replays, heatmaps or performance timings, the script loads a small extra module from the same origin at runtime. That is a script load, so script-src must allow the origin, not just connect-src.

A nonce-only policy will block those modules, because a script added at runtime carries no nonce. Either list the origin explicitly, or add 'strict-dynamic' so scripts loaded by an already-trusted script are allowed.

Through a tag manager

Installing through Google Tag Manager adds the tag manager’s own requirements on top. Both origins have to be allowed, and the same 'strict-dynamic' point applies, because the tag manager injects the Statsy tag at runtime.

Testing a policy change safely

Ship the new policy as Content-Security-Policy-Report-Only first. The browser reports what it would have blocked without breaking anything, so you can confirm the directives are right before enforcing them.

Last updated · Markdown version