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:
<script
src="https://cdn.consentlab.eu/widget/v1/consentlab.min.js"
data-cc-key="YOUR_API_KEY"
nonce="{NONCE}"
defer
></script>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:
// 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):
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 toscript-src(see next section). - The trailing
https:inscript-srcis 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 viadata-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) inscript-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:
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.
Consent is accepted but has no effect
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:
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.