Fix a Content Security Policy that is blocking DataSpice

A Content-Security-Policy that does not name the DataSpice origin makes the browser refuse the tracking script, and a refused script sends nothing — so the dashboard stays empty and looks exactly as it would if the snippet had never been pasted. The fix is two entries in a header you already control. This page shows which two, how to confirm that CSP really is the cause, and where the header is usually set.

What a Content-Security-Policy does to the tracking script

A Content-Security-Policy is an allowlist your site sends to the browser, naming every origin that is permitted to supply scripts, images, styles and network calls. Anything not on the list is refused before it runs. This is the whole point of the mechanism, and it applies to us exactly as it applies to any other third party: a policy written before you installed DataSpice does not name our origin, so the browser blocks the script. Nothing about that block reaches us, which is why the dashboard cannot tell you about it on its own.

No analytics vendor can work around this, and you should be suspicious of one that claims to. A third-party script that could talk its way past a policy would be a browser vulnerability, not a feature. What a vendor can do is tell you clearly that one entry is needed — which is what this page is.

The two directives DataSpice needs, and why one is not enough

Add the DataSpice origin to both `script-src` and `connect-src`. The first lets the browser fetch the tracker file; the second lets that file deliver what it records. Allowing only `script-src` is the most common half-fix: the script loads, appears to be installed, and then silently fails on every event it tries to send.

script-src  'self' ... https://backend.dataspice.net;
connect-src 'self' ... https://backend.dataspice.net;

The origin above is the one used by DataSpice Cloud. If you were given a different tracker URL, use its origin instead — the exact value for your account is shown in the dashboard under the install snippet.

`connect-src` covers `navigator.sendBeacon` as well as `fetch`, and the tracker prefers `sendBeacon` so that events survive a page being closed. Both go through the same directive, so there is nothing else to add.

How to tell whether CSP is why your dashboard is empty

Open your site, open the browser console, and look for a message naming the policy. A blocked tracker says so explicitly, and the wording tells you which directive refused it.

Loading the script 'https://backend.dataspice.net/tracker/v1.js?...' violates
the following Content Security Policy directive: "script-src 'self' ...".

DataSpice also checks this for you. On a website that has never reported an event, the tracking settings screen reads your site's real policy and says whether it admits the tracker — and when it does not, it hands back your own policy with the missing entries added and nothing else changed, ready to paste.

You can read the header yourself with one command. An empty result means your site sends no policy, and CSP is not your problem.

curl -sI https://yourdomain.com | grep -i content-security-policy

Where the Content-Security-Policy header is usually set

The header comes from whatever serves your HTML, and on most sites that is not the application code — which is why the person who wrote your site often does not remember setting one. Search these in order.

Common places a policy is defined
Where the site runsWhat to open
Apache, LiteSpeed, or shared hosting such as Hostinger or cPanel`.htaccess` in the site root — look for `Header set Content-Security-Policy`
nginxThe server block — `add_header Content-Security-Policy`
Cloudflare in front of any originRules to Transform Rules to Modify Response Header
Netlify, or Cloudflare PagesThe `_headers` file in the published output
Vercel, or Next.js on any host`headers()` in `next.config.js`, or `vercel.json`
A WordPress security pluginIts headers or hardening screen; several write the policy into `.htaccess`
A static site with no server configA `<meta http-equiv="Content-Security-Policy">` tag in the HTML

Change the value in place: add the origin to the two directives and leave everything else exactly as it is. There is never a reason to remove the policy or to widen it with `*` — that trades a working tracker for the protection the policy was added to provide.

Serving the tracker from your own domain instead of editing the policy

If the policy is out of your hands, proxy the tracker through your own domain so it arrives as a same-origin script and `'self'` already covers it. No CSP entry is then needed at all. The tracker derives its reporting endpoint from the URL it was loaded from, so events follow the same path automatically.

location /ds/ {
    proxy_pass https://backend.dataspice.net/;
    proxy_set_header Host backend.dataspice.net;
}

Then load the script from `https://yourdomain.com/ds/tracker/v1.js?...` instead. This has a second benefit worth the setup on its own: content blockers filter known analytics domains and will not filter yours, so the measurement is more complete than it would otherwise be.

Confirming the fix has taken effect

Re-read the header and confirm the origin appears twice — once for each directive. One occurrence means only half the change landed, which will look like an installed tracker that reports nothing.

curl -sI https://yourdomain.com | tr ' ' '\n' | grep dataspice
  1. Deploy the header change.
  2. Purge the CDN cache if one sits in front of the site; a cached response carries the old header with it.
  3. Open the site in a fresh tab and confirm the console no longer names DataSpice.
  4. Watch the live view in the dashboard — the first page view arrives within seconds of a real visit.

If the header is correct and events still do not arrive, the cause is elsewhere: check that the snippet is present on every page rather than one, and that the domain in the snippet matches the hostname visitors actually land on. A site serving both `example.com` and `www.example.com` reports only from the one the snippet names.