Security & CSP
What the browser script can and can't do, the Content-Security-Policy directives it needs, and why the proxy install is the strongest setup.
A script in your <head> runs with full page privileges, so it's fair to ask what ours actually does before you ship it. This page is the honest answer, plus the exact CSP directives to lock it down.
What the script can and can't do
The SDK is a single minified IIFE. You can read the whole thing — it's served unobfuscated at https://cdn.datalook.app/s.js.
| Property | Status |
|---|---|
eval, Function(), innerHTML | None. Nothing dynamic to inject into. |
Cookies / localStorage | Not used. The visitor id is hashed server-side; the browser stores no identifier. |
| Active fingerprinting (canvas, WebGL, fonts) | None. |
| Credentials on requests | Omitted (credentials: 'omit'). No cookies ride along. |
| Global footprint | One global, window.analytics. No prototype patching. |
| Failure isolation | Sends are wrapped in try/catch; a bot context gets no-op stubs. A failure can't throw into your render. |
| PII in custom properties | Keys matching email / phone / password / ssn are dropped in the browser and again server-side. |
One global we do touch
To track route changes in single-page apps, the SDK wraps history.pushState and replaceState (it calls your original and preserves its return value). This is standard for SPA analytics. It's the only host global we touch.
What we collect from the browser
Beyond the URL, referrer, and UTM tags, each event carries a small env object: screen and viewport size, device pixel ratio, color depth, language, and timezone. This is passive context, not active fingerprinting — but it's not nothing, so we name it here rather than hide it. No PII, no canvas hashes, no font enumeration.
Content-Security-Policy
The SDK needs no unsafe-inline and no unsafe-eval — it's an external script that only loads and sends data. If you run a CSP, allow our origin for loading (script-src) and sending (connect-src):
script-src 'self' https://cdn.datalook.app;
connect-src 'self' https://cdn.datalook.app;connect-src covers both navigator.sendBeacon and the fetch fallback.
The proxy install needs no third-party origin at all
Once you've done the first-party proxy setup, the script and the collector both come from your own domain — so the directives collapse to:
script-src 'self';
connect-src 'self';There's no external origin to allowlist, nothing for an ad blocker to match, and a tighter CSP. It's the strongest of the two setups on every axis.
Why there's no SRI hash
Subresource Integrity pins a script to a fixed hash. We ship fixes and improvements to s.js on the CDN, so a pinned hash would break the moment we update — the same constraint every auto-updating analytics script lives with. Instead, the script is small enough to read end to end, and the proxy install lets you serve it from infrastructure you control.
Transport details
navigator.sendBeacon(<endpoint>, body)with afetch({ keepalive: true })fallback.Content-Type: text/plainso the request is a CORS simple request — no preflight to misconfigure.- The endpoint is resolved relative to the script's URL (see the proxy overview).
What's next
- Lock down the third-party origin entirely with the first-party proxy.
- The full privacy stance (cookieless ids, IP handling) lives on the marketing site's privacy page.