← Documentation

ConsentLab + CSP

Run the cookie banner under a strict, nonce-based Content-Security-Policy — without ever adding unsafe-inline.

1. Why a strict CSP

A strict Content-Security-Policy (CSP) is one of the best protections against XSS attacks: the browser only executes the scripts and styles your policy explicitly allows, via a nonce generated by your server on every request.

Many third-party tools ask you to add 'unsafe-inline' to your policy to work. Never do it: it defeats most of the protection your CSP provides, for your entire site.

ConsentLab does not need it: the widget picks up your page's nonce at load time and applies it automatically to everything it injects — its styles and the scripts it unblocks after consent.

2. Integration

Recommended: the native nonce attribute

Set the standard nonce attribute on the loader tag, exactly like any other script on your page. Replace {NONCE} with the value your server generates on each request:

html
<script
  src="https://cdn.consentlab.eu/widget/v1/consentlab.min.js"
  data-cc-key="YOUR_API_KEY"
  nonce="{NONCE}"
  defer
></script>
That's it. The widget reads the nonce from its own tag at boot and propagates it to everything it injects. No extra attribute, no configuration.

Alternative: data-cc-nonce (dynamically injected loader)

Browsers clear the nonce attribute of elements inserted into the DOM (anti-exfiltration protection). If your loader is injected dynamically (tag manager, init script…), the widget cannot read the native nonce back: pass it via data-cc-nonce as well:

js
// Only if the loader is injected dynamically.
const s = document.createElement('script');
s.src = 'https://cdn.consentlab.eu/widget/v1/consentlab.min.js';
s.defer = true;
s.dataset.ccKey = 'YOUR_API_KEY';
s.dataset.ccNonce = nonce; // the current page's CSP nonce
s.nonce = nonce;           // required to execute the loader itself
document.head.appendChild(s);
data-cc-nonce is reserved for this exact case, and must be set on the ConsentLab loader tag only: the widget uses the first script[data-cc-nonce] in the document. For a classic HTML integration, use the native nonce attribute above.

3. Recommended policy

Example of a strict policy compatible with ConsentLab (and your other scripts):

http
Content-Security-Policy:
  script-src 'nonce-{NONCE}' 'strict-dynamic' https:;
  style-src 'nonce-{NONCE}';
  connect-src 'self' https://api.consentlab.eu;
  • With 'strict-dynamic', scripts created by our nonced loader inherit its trust (modern browsers) — scripts unblocked on consent run without allowlisting every third-party domain.
  • Injected styles, however, always need the nonce — 'strict-dynamic' only applies to scripts. That is why the widget propagates the nonce natively.
  • Without 'strict-dynamic', it works too: the widget sets the nonce everywhere it is needed (styles and executable script copies). In that case add the origins of external scripts to script-src (see next section).
  • The trailing https: in script-src is a fallback for browsers that do not support 'strict-dynamic'(browsers that do support it ignore it).

4. Origins to allow

  • connect-src https://api.consentlab.eu — the widget loads its configuration and records consent proofs there. If you point the widget to another instance via data-cc-api, allow that origin instead.
  • script-src https://cdn.consentlab.eu — only if the loader comes from the CDN and your policy does not use 'strict-dynamic' (otherwise the nonce on the tag is enough).
  • The domains of the tools you unblock on consent (for example www.googletagmanager.com, *.google-analytics.com) in script-src / connect-src, as their docs require — unless 'strict-dynamic' already covers their scripts.

5. Troubleshooting

Two typical symptoms when the nonce does not reach the widget — in both cases, the developer console (F12) shows explicit CSP violations.

The banner shows up "bare", with no styling

Your style-src directive blocks the styles the widget injects. In the console:

console
Refused to apply inline style because it violates the following
Content Security Policy directive: "style-src 'nonce-…'".

Usual cause: the loader tag has no nonceattribute (or the nonce does not match the header's). Check that the nonce is generated on every request and set on the tag.

The banner works, the choice is saved, but the blocked scripts (type="text/plain" + data-cc) never run: your script-src blocks the executable copies the widget creates on unblock. In the console:

console
Refused to execute inline script because it violates the following
Content Security Policy directive: "script-src 'nonce-…'".

Same cause, same fix: the widget can only propagate the nonce it received via its tag (nonce attribute or data-cc-nonce).

6. FAQ

Need help with your CSP?

Send us your CSP header and the console violations: our team replies within 24h.