Data4/Content-Security-Policy Analytics: CSP Setup Guide

Content-Security-Policy Analytics: CSP Setup Guide

Learn how to configure Content-Security-Policy for analytics tools like GA4 and Data4, fix blocked tracking scripts, and keep CSP tight without losing data.

ABy Anonymous15 min read

Content-Security-Policy Analytics: How to Allow Tracking Without Weakening Security

A strict Content-Security-Policy (CSP) is one of the best defenses against cross-site scripting, but it is also one of the most common reasons analytics stops working. The moment you add default-src 'none' or drop 'unsafe-inline', your tracking script, its configuration snippet, and its data-collection endpoint can all be blocked silently. Your dashboard shows zero sessions, and nothing in the browser console looks like a normal error.

This guide explains how CSP and analytics interact, shows working policies for GA4 and lightweight tools, and covers the trade-offs between nonces, hashes, and host allowlists so you can keep both your security posture and your data.

Why CSP Breaks Analytics in the First Place

Content-Security-Policy Analytics: CSP Setup Guide - Why CSP Breaks Analytics in the First Place

Content-Security-Policy Analytics: CSP Setup Guide - Why CSP Breaks Analytics in the First Place.

CSP is delivered as a response header (or a <meta http-equiv> element) that lists directives telling the browser which resources a page may load. According to the MDN CSP guide, each directive controls one resource category: script-src for JavaScript, img-src for images, connect-src for XHR, fetch, and beacon requests, and default-src as the fallback for anything not explicitly listed.

Analytics tools typically need three separate permissions:

  1. A script load — the tag manager or vendor script itself, usually from a CDN domain.
  2. A configuration or inline snippet — the small block that sets your measurement ID and initializes the tracker.
  3. A data endpoint — the domain that receives the collected events, often via fetch or navigator.sendBeacon.

Miss any one of the three and tracking fails. A blocked script produces a console CSP violation; a blocked connect-src endpoint is quieter, because the request simply never leaves the browser.

A Minimal Working CSP for Google Analytics 4

Content-Security-Policy Analytics: CSP Setup Guide - A Minimal Working CSP for Google Analytics 4

Content-Security-Policy Analytics: CSP Setup Guide - A Minimal Working CSP for Google Analytics 4.

The CSP examples for Google Analytics recommend moving the inline gtag snippet into an external file so you do not need 'unsafe-inline'. A compact policy looks like this:

Content-Security-Policy: default-src 'self'; script-src 'self' https://www.googletagmanager.com; connect-src 'self' https://www.google-analytics.com https://region1.google-analytics.com;

Three details matter here:

  • script-src must include https://www.googletagmanager.com, because that is where gtag/js is served from.
  • connect-src must include the collection endpoint. In the EU, Google may route through region1.google-analytics.com, so either list both regional hosts or use https://*.google-analytics.com.
  • default-src 'self' is safer than 'none' for most sites, because 'none' also blocks your own CSS, fonts, and images unless you enumerate every directive.

If you keep the inline snippet, you need a nonce or hash instead of a host allowlist. Nonces are generated per response and inserted into both the header and the <script> tag; hashes are computed from the script contents and prefixed with sha256-, sha384-, or sha512-. Nonces require server-side templating, so static hosting usually pushes teams toward hashes or an external script file.

How CSP Works for Lightweight and Privacy-First Analytics

Tools that avoid tag managers tend to need fewer directives. The Simple Analytics CSP documentation is a useful reference pattern: one host for the public script, one host for the beacon endpoint, and one host for badge images.

Content-Security-Policy: script-src 'self' https://scripts.example-analytics.com; connect-src 'self' https://queue.example-analytics.com; img-src 'self' https://queue.example-analytics.com;

This pattern generalizes well. Whatever platform you use, the audit is the same: open DevTools, filter the Network tab by the analytics domain, and confirm that the script request returns 200 and the collection request is not marked as blocked. Then check the Console for Refused to load or Refused to connect messages, which name the exact directive that rejected the request.

If you are evaluating platforms partly on how simple their CSP footprint is, a side-by-side comparison such as Data4 vs Plausible Analytics vs Google Analytics helps you weigh script weight and endpoint count alongside reporting depth.

Choosing Between Nonces, Hashes, and Host Allowlists

Content-Security-Policy Analytics: CSP Setup Guide - Choosing Between Nonces, Hashes, and Host Allowlists

Content-Security-Policy Analytics: CSP Setup Guide - Choosing Between Nonces, Hashes, and Host Allowlists.

Approach Best for Trade-off
Host allowlist in script-src External analytics files Any script on that host is trusted
Nonce Dynamic, server-rendered pages Requires per-response templating
Hash Static pages, fixed snippets Breaks whenever the snippet changes
'unsafe-inline' Legacy setups only Removes a core XSS protection

A practical middle ground for most teams is a host allowlist for the vendor script plus a nonce for your own inline bootstrap code. That keeps third-party trust narrow while still letting you configure the tracker.

Common CSP Errors and How to Fix Them

Analytics loads but no data arrives. The script executed, so script-src is fine, but connect-src is missing the collection domain. Add the endpoint host and redeploy the header.

Everything works in staging, nothing in production. Staging often has a looser policy or no CSP at all. Diff the two headers before debugging anything else.

The policy works, then breaks after a vendor update. Vendors change endpoints and CDN hosts. Pinning a full URL in connect-src is more restrictive but brittle; a wildcard subdomain is more resilient but broader.

You cannot tell what is being blocked. Deploy Content-Security-Policy-Report-Only first. It logs violations without enforcing them, so you can build a complete allowlist from real traffic before switching to enforcement.

Rolling Out a CSP Change Without Losing Data

  1. Inventory every analytics request. Load your site with the Network tab open and record each domain contacted.
  2. Start in report-only mode. Collect violations for at least a full traffic cycle, including campaign landings and checkout flows.
  3. Write the enforced policy. Include your own assets, not just the analytics hosts.
  4. Verify end to end. Confirm the script loads, the beacon fires, and events appear in your analytics dashboard.
  5. Monitor after release. Keep reporting enabled at a low sample rate so vendor endpoint changes surface early.

If you are switching platforms at the same time, follow a structured migration process rather than changing CSP and vendor in one release. A guide like Replace Google Analytics With a Privacy Tool covers sequencing, data continuity, and how to validate that the new endpoint is actually receiving events under your new policy.

Where Data4 Fits Into a CSP Setup

Data4 is a website analytics platform positioned as a simpler alternative to Google Analytics, with real-time traffic tracking, audience segmentation, conversion analysis, and customizable dashboards. For CSP purposes, what matters is its request footprint: a single script host and a single collection endpoint, which means two directives rather than the tag-manager-plus-regional-endpoint pattern GA4 often requires.

The practical effect is a shorter, easier-to-audit policy — fewer hosts in script-src, fewer hosts in connect-src, and less chance that a regional routing change silently breaks collection. If your team has struggled to keep a strict CSP stable across multiple analytics vendors, comparing tools on that dimension is worth doing before you commit; Data4 vs Clicky vs Umami breaks down privacy posture, real-time tracking, and reporting depth for that kind of decision.

Related reading

FAQ

Does Content-Security-Policy block Google Analytics by default?

No. CSP only blocks analytics if your policy does not allow the required hosts. A policy without script-src and connect-src entries for the analytics domains will block tracking, but a permissive or absent policy will not.

Which CSP directive does analytics need?

Three, usually: script-src for the tracking script, connect-src for the data endpoint, and img-src if the tool uses pixel-based tracking or serves badge images.

Can I use CSP with an inline analytics snippet?

Yes, but you must authorize it with a nonce or a hash. 'unsafe-inline' also works, though it removes a significant layer of XSS protection and is best avoided on public-facing sites.

Why does analytics work locally but fail in production?

Local and staging environments frequently have no CSP header or a much looser one. Production headers are usually stricter, so the same script that loaded locally gets refused in production.

How do I test a CSP change safely?

Use Content-Security-Policy-Report-Only to log violations without blocking anything, collect reports across real user sessions, then move the verified policy into the enforcing Content-Security-Policy header.

Conclusion

CSP and analytics are not in conflict — they just need to be configured together. Identify the script host and the collection endpoint for your analytics platform, add them to script-src and connect-src, handle any inline snippet with a nonce or hash, and roll the change out through report-only mode. Do that, and you keep the XSS protection CSP was designed to provide without watching your traffic data disappear.