# Content Security Policy

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

Section: Troubleshooting  
Canonical page: https://statsy.co/docs/troubleshooting/csp  
Last updated: 2026-09-15

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](https://statsy.co/docs/troubleshooting/no-data).

## 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](https://statsy.co/docs/tracking-script/first-party-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.

Previous: [Script installed but no data](https://statsy.co/docs/troubleshooting/no-data)  
Next: [Ad blockers and the proxy host](https://statsy.co/docs/troubleshooting/ad-blockers)