Skip to content

Documentation

ConsentLab + CSP

01 · Why

A strict CSP, without unsafe-inline

A strict Content-Security-Policy 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.

02 · Integration

Set the nonce on the loader

Recommended: the native nonce attribute

Set the standard nonce attribute on the loader tag, exactly like any other script on your page, with the value your server generates on each request (snippet on the right).

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 (snippet on the right).

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.

03 · Policy

The recommended policy

Example of a strict policy compatible with ConsentLab and your other scripts (right-hand column).

  • 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 (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).

04 · Origins

What your policy must 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.

05 · Troubleshooting

Two symptoms, one cause

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

The banner shows up bare, with no styling

Your style-src directive blocks the styles the widget injects. Usual cause: the loader tag has no nonce attribute, or the nonce does not match the header’s. Check that the nonce is generated on every request and set on the tag.

06 · FAQ

Nonce, meta tag and edge cases

Do I need to add 'unsafe-inline' for ConsentLab?

No, never. The widget is designed for nonce-based policies: set the nonce on the loader tag and it is propagated to every injection (styles and scripts). Adding 'unsafe-inline' would weaken XSS protection for your entire site.

My site has no CSP, do I need to do anything?

No. When no nonce is detected, the widget’s CSP support is fully inactive: no attribute added, no behaviour change.

Why the nonce if I already use 'strict-dynamic'?

'strict-dynamic' only covers scripts: the styles the widget injects (banner, preferences modal, consent walls) still require a valid nonce under style-src. And if your policy does not use 'strict-dynamic', the nonce is also propagated to the scripts unblocked on consent.

I use a CSP meta tag, not a header: compatible?

Yes, the mechanism is identical: the browser enforces the policy from the <meta http-equiv> tag and the widget propagates the nonce the same way. The HTTP header remains recommended (it covers more directives and applies earlier).

Need help with your CSP?

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

The tag with nonce

<script
  src="https://cdn.consentlab.eu/widget/v1/consentlab.min.js"
  data-cc-key="YOUR_API_KEY"
  nonce="{NONCE}"
  defer
></script>

Dynamically injected loader

// 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);

Recommended policy

Content-Security-Policy:
  script-src 'nonce-{NONCE}' 'strict-dynamic' https:;
  style-src 'nonce-{NONCE}';
  connect-src 'self' https://api.consentlab.eu;

Violation · styles

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

Violation · scripts

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