Reference — Content-Security-Policy for the LoudPixel pixel

The exact CSP directives the LoudPixel attribution pixel needs, including a SHA-256 hash for the inline queue stub so you never need 'unsafe-inline'.

If your site sends a Content-Security-Policy header, the pixel needs three directives. Without them the browser blocks it silently — your pages look fine, the console shows a CSP violation, and your dashboard shows zero events forever.

The short version

script-src  https://loudpixel.ai 'sha256-FMheJwvj8IrbXYYNzgQaXAhWC3JNf4Zm8jpCl80/3FY=';
connect-src https://loudpixel.ai;
img-src     https://loudpixel.ai;

Add these to your existing directives — do not replace them. CSP directives are allowlists, so append the values above to whatever you already have on each line.

What each one is for

DirectiveWhy the pixel needs it
script-src https://loudpixel.ailoads /t.js
script-src 'sha256-…'allows the one inline stub in the install snippet
connect-src https://loudpixel.aisendBeacon / fetch to /api/v1/track/pixel and /track/pixel/goal — this is how events actually reach us
img-src https://loudpixel.aionly if you use the /p.gif image fallback (email, AMP, RSS)

connect-src is the one people miss. Allow the script but not the connection and the pixel loads, runs, and every event it sends is blocked — the most confusing possible failure, because nothing on the page looks wrong.

The pixel needs nothing else: no cookies, no localStorage, no style-src, no frame-src, no 'unsafe-eval'.

Why there is a hash

The install snippet is two lines, and the first is inline:

<script>window.lp=window.lp||{};window.lp.track=window.lp.track||function(){(window.lp.q=window.lp.q||[]).push(arguments)};</script>
<script async src="https://loudpixel.ai/t.js?domain=yourdomain.com"></script>

That stub exists so lp.track('checkout', …) on your thank-you page works even before the async script has finished loading — it queues the call and the pixel replays it on arrival. Without it, that call throws ReferenceError: lp is not defined on exactly the page where your money is.

Being inline, it needs one of three things under CSP: 'unsafe-inline', a nonce, or a hash. The hash above is the SHA-256 of that exact stub text, so you can keep a strict policy. The hash covers the bytes between the tags exactly — if you reformat the stub, add whitespace, or change a character, the hash no longer matches and the browser blocks it. Copy it verbatim, or use a nonce instead:

<script nonce="YOUR_REQUEST_NONCE">window.lp=window.lp||{};window.lp.track=window.lp.track||function(){(window.lp.q=window.lp.q||[]).push(arguments)};</script>

If your page never calls lp.track(), drop the stub entirely and you need no hash, no nonce, and no 'unsafe-inline' — just the script-src, connect-src and img-src origins.

If you proxy the pixel from your own domain

Customers who serve /t.js from their own origin (for ad-blocker resistance) pass ?api=/api/v1, which makes every request same-origin. In that case you need no LoudPixel origin at all — 'self' covers it.

Checking it worked

Open DevTools on a page that has the pixel:

  1. Console — a blocked pixel says so explicitly: "Refused to load the script" or "Refused to connect", naming the directive that blocked it. That message names your fix.
  2. Network — you should see t.js return 200, then a POST to /api/v1/track/pixel shortly after. The POST is the one that matters; a 200 on t.js alone proves nothing.

Report-only first, if you prefer

Content-Security-Policy-Report-Only applies the same rules and blocks nothing, so you can add the pixel, watch for violations for a day, and only then move the directives to the enforcing header.