Native CMP

Documentation

Native CMP

Everything you need to install, configure, translate, style and extend the consent manager. Looking for ready-made service setups? See the examples.

Overview

Native CMP is a consent manager for cookies, third-party scripts and embeds, built from regular Webstudio building blocks. There is no external service, dashboard or vendor script: everything lives in your project and can be edited in the Builder.

  • Engine: a small script in Project Settings → Custom Code. It reads the stored decision before the page paints, blocks and activates third-party code, deletes cookies and keeps everything in sync during client-side navigation.
  • Consent Manager Slot: the notice, preferences modal, purposes and switches as native instances, shared across all pages.
  • Variables: consentServices describes what each service does technically; consentTranslations holds all copy per language.
  • Attributes: behavior is wired with data-cmp-* attributes, so any element you design can open the settings, show a status or wait for consent.
  • Craft tokens: every part of the UI is a composite Token backed by semantic CSS variables.

Native CMP is free and open source under the AGPL-3.0-or-later license. The source code, build scripts and tests are on GitHub.

The CMP gives you technical building blocks for a GDPR- and ePrivacy-friendly setup: prior blocking, granular purposes, equally prominent choices, revocation and cookie cleanup. Whether a site is compliant also depends on its texts, services and privacy policy.

Installation

Install with an AI agent (recommended)

Connect Claude Code, Codex, Cursor or any agent to your project with the Webstudio MCP (npx webstudio@latest link with a Builder share link, then npx webstudio@latest connect) and ask it to follow nativecmp.com/install.txt. The agent:

  • scans Custom Code, HTML Embeds and YouTube or Vimeo components and recognizes 23 common services,
  • installs the engine, design tokens and the Consent Manager Slot on every page,
  • configures each service with its cookies and descriptions in your site’s languages,
  • blocks scripts and wraps embeds and videos in Consent Gates,
  • adds a section per service to your privacy policy, for you to review,
  • maps the consent UI to your colors, radii and fonts and verifies the result.

It shows you its plan before changing anything and never publishes. See Install with AI for the prompt. Prefer to do it yourself? Use the generator, copy from the examples or follow the manual steps below.

Starting a new site? Clone the Native CMP Starter, a Webstudio project with the engine, the Consent Manager, a Consent preview page and example gates already set up. See it live at starter.nativecmp.com.

Manual installation

1. Add the engine

Open Project Settings → Custom Code and paste the CMP snippet at the very top, before any analytics or tag manager code. It contains three parts:

Custom Code

<!-- Native CMP: configuration -->
<script>
window.cmpConfig = {
storageName: "cmp_consent",
cookieExpiresAfterDays: 365,
};
</script>
<style data-cmp-critical>/* critical CSS */</style>
<script data-cmp-engine="1.1.0">/* engine */</script>
<!-- Consent-managed head scripts go below this line -->

2. Add the Consent Manager Slot

Copy the Consent Manager Slot to every page. On new projects, add it to your page template so new pages include it automatically. The Slot is shared: editing it on one page updates every page.

3. Configure services and copy

Select the Consent Manager root instance and edit the consentServices and consentTranslations variables in the Data panel. The examples contain ready-made entries for the most common services.

4. Block third-party code

Change existing scripts and embeds so they only run with consent (see Blocking scripts & embeds) and add a Privacy settings link to your footer with data-cmp-action="open-modal".

5. Publish and test

Open the site in a private window. The notice must appear, nothing tracked should load before a decision, and your choice must survive reloads and page changes. cmp.getConsents() in the browser console shows the current state.

How it works

  • Before the first paint: the engine runs in <head>, reads the cmp_consent cookie and sets state attributes on <html>. The critical CSS uses them to show or hide the notice immediately, so returning visitors never see a flash.
  • After the page is parsed: the engine reads the service definitions from the Slot, validates the stored decision, activates allowed scripts and embeds, and renders switches, gates and status indicators.
  • During client-side navigation: Webstudio remounts page content on every route change. A MutationObserver notices new consent-related elements and re-syncs them. Consent state lives in the engine, not in the page, so it survives navigation.
  • No double execution: React may re-create embed content (for example right after hydration). The engine remembers what it has already executed per embed container, so scripts never run twice.

Effective consent

A service is active when it is required, when the visitor accepted it once in a gate, or when it has consent and the decision is confirmed. Services marked optOut also run before a decision, until the visitor declines them.

Changed services

If the service list changes after a visitor decided, the stored decision becomes unconfirmed: the notice opens again with the “services changed” message, and non-required services stay blocked until the visitor decides again.

Configuration

Set options in window.cmpConfig at the top of the Custom Code snippet. All options are optional.

OptionDefaultDescription
storage"cookie"Where the decision is stored: "cookie" or "localStorage".
storageName"cmp_consent"Cookie or localStorage key.
cookieExpiresAfterDays365Lifetime of the consent cookie.
cookieDomain""Set e.g. ".example.com" to share consent across subdomains.
cookiePath"/"Path of the consent cookie.
defaultfalsePreselection for services without their own default.
mustConsentfalseOpen the preferences modal instead of the notice. It can’t be closed until the visitor decides.
noNoticefalseContextual consent only: no notice on page load. Consent Gates, Privacy settings links and the JavaScript API ask for consent. See Contextual consent only.
confirmDelay800Milliseconds the modal stays visible after Accept all / Decline all, so visitors see the switches change.
consentModenullGoogle Consent Mode v2 mapping, see Google Consent Mode & GTM.
consentModeDefaultsnullExtra fields for gtag("consent", "default", …), e.g. { security_storage: "granted" }.
dataLayerfalsePush { event: "cmp_consent", cmp_type, cmp_consents } to window.dataLayer on every decision.
fallbackLanguage""Language shown when no translation matches the page. Defaults to the first entry.
debugfalseLog service definitions and cookie deletions to the console.

Set noNotice: true if you only want to protect embeds such as YouTube or Google Maps and don’t need a notice on page load. The generator calls this Contextual consent only. Visitors allow a provider right where its content appears: Load content allows it for the current page, Always allow stores the decision straight away. The Privacy settings link still opens the full preferences.

In this mode the root gets data-cmp-mode="contextual", and Always allow buttons are visible before any decision. Head scripts such as analytics stay blocked until visitors enable them in the preferences, so use it for sites without consent-based tracking. mustConsent takes precedence if both are set.

Stored value

The cookie contains URL-encoded JSON: { "consents": { "google-analytics": true, … }, "timestamp": "2026-09-13T10:00:00.000Z", "version": 1 }. The timestamp documents when the decision was made.

Services

consentServices is a JSON array on the Consent Manager root. It is rendered as a hidden Service Registry that the engine reads.

consentServices

[
{ "name": "consent-manager", "required": true },
{ "name": "google-analytics", "cookies": ["^_ga", "_gid", "^_gat"] },
{ "name": "youtube" },
{ "name": "chat", "optOut": true, "dependsOn": ["google-analytics"] }
]
FieldTypeDescription
namestringUnique key. Referenced by data-cmp-service, data-cmp-gate, data-cmp-status and translations. Use lowercase and dashes.
requiredbooleanAlways active. The switch is disabled and the “Always active” badge is shown.
defaultbooleanPreselected in the preferences modal before the visitor decides.
optOutbooleanRuns before a decision, until the visitor declines. Shows “Active by default”.
cookiesstring[]Cookies deleted when consent is missing or revoked. Patterns starting with ^ are regular expressions (^_ga matches _ga_ABC123); other values match exactly. No spaces inside a pattern.
onlyOncebooleanAccept scripts run at most once per page load, even across client-side navigation.
contextualOnlybooleanIgnored by Accept all / Decline all. Only its switch or a Consent Gate changes it.
dependsOnstring[]Enabling this service enables the listed services; disabling one of them disables this service.

Cookie deletion works for first-party cookies the browser lets JavaScript see: the current host, the host with a leading dot and every parent domain, on path / and the current path. HttpOnly cookies and cookies on third-party domains can’t be removed from the page.

Languages & translations

consentTranslations contains one entry per language. The Slot renders one notice and modal per entry and the engine shows the one matching the page language from Page Settings → Language (rendered as <html lang>).

consentTranslations

[
{
"lang": "en",
"dir": "ltr",
"privacyLabel": "privacy policy",
"privacyUrl": "/privacy",
"notice": {
"title": "We value your privacy",
"text": "We use cookies … Learn more in our",
"changes": "Our services have changed since your last visit.",
"customize": "Customize", "decline": "Decline all", "accept": "Accept all"
},
"modal": {
"title": "Privacy settings", "text": "Choose which services we may use …",
"close": "Close privacy settings", "toggleAll": "Enable or disable all services",
"alwaysActive": "Always active", "activeByDefault": "Active by default",
"service": "service", "services": "services",
"decline": "Decline all", "save": "Save selection", "accept": "Accept all"
},
"purposes": [
{
"id": "analytics", "title": "Analytics", "description": "…",
"services": [
{ "name": "google-analytics", "title": "Google Analytics", "description": "…" }
]
}
]
}
]

Language matching

  • Exact match, case-insensitive: de-AT → de-at.
  • Primary language: de-AT → de, or a regional entry of the same language.
  • cmpConfig.fallbackLanguage, otherwise the first entry.

The language updates live when client-side navigation changes <html lang>. Consent is shared across languages. Purposes group services in the modal; a purpose switch toggles all its non-required services and shows a mixed state when only some are active.

Any language

  • Add an entry with any language code: fr, pt-BR, tr, fa, …. The engine doesn’t need a list of supported languages.
  • The generator includes built-in notice, modal, purpose and gate texts and descriptions for all 23 catalog services in English, German, Spanish, French, Italian, Portuguese, Dutch, Polish, Arabic and Hebrew.
  • For other codes the generator starts from English and marks every field English – translate in its translation editor. The editor also imports translations from pasted configurations.

Right-to-left languages

Each entry may set "dir": "rtl" or "ltr". Without it, the Consent Manager detects right-to-left from the language code: ar, arc, ckb, dv, fa, he, ku, ps, sd, ug, ur and yi. The language wrapper gets the matching dir attribute, so the notice, modal and switches mirror automatically.

  • Layouts use flex and grid, which follow the writing direction.
  • Tokens that need explicit mirroring use logical properties or the :dir(rtl) state. For example, consent-switch mirrors its thumb and consent-modal-close uses margin-inline-end.
  • Set dir="rtl" on the Body of right-to-left pages too, so your own page content mirrors as well. See the Arabic demo.

Other translated elements

Add data-cmp-lang="de" to any element, for example a footer link in a shared Slot, to show it only on German pages.

Blocking scripts & embeds

Mark third-party code with data-cmp-service. Put it in Custom Code (runs once per visit) or an HTML Embed (runs on the pages that contain it).

External scripts

HTML

<script type="text/plain" data-cmp-service="google-analytics"
data-src="https://www.googletagmanager.com/gtag/js?id=G-XXXX"></script>

type="text/plain" stops the browser from running the script. On consent the engine inserts a real copy into <head> with all other attributes (id, data-*, nonce, async). Use data-type to restore a type such as module. The same external URL is only loaded once per page load.

Inline scripts and decline handlers

HTML

<script type="text/plain" data-cmp-service="google-analytics">
gtag("config", "G-XXXX");
</script>
<script type="text/plain" data-cmp-service="google-analytics" data-cmp-on="decline">
window["ga-disable-G-XXXX"] = true;
</script>

Inline scripts run when consent is granted, again after a revoke followed by a new consent, and once for every page that renders them. data-cmp-on="decline" runs a script when the service is denied or revoked.

Templates for iframes and widgets

HTML Embed

<template data-cmp-service="youtube">
<iframe src="https://www.youtube-nocookie.com/embed/VIDEO_ID" title="Video"></iframe>
</template>

Everything inside a <template> is inert. On consent the content is inserted after the template (scripts go to <head>); on revoke it is removed again. This is the most robust option for iframes, widgets and social embeds.

Attribute swapping

HTML

<iframe data-cmp-service="vimeo" data-src="https://player.vimeo.com/video/ID"></iframe>
<img data-cmp-service="tracker" data-src="https://example.com/pixel.gif" alt="">
<link rel="stylesheet" data-cmp-service="google-fonts" data-href="https://fonts.googleapis.com/…">

For other elements the engine copies data-src, data-srcset, data-href, data-poster and data-data into the real attributes on consent and removes them on revoke (iframes switch to about:blank). Iframes, images, video, audio, embed and object elements stay hidden until granted. Stylesheet links are added to and removed from <head>.

For YouTube and Vimeo, use Webstudio’s native components inside an interaction-mode Consent Gate (see Consent Gates). Turn off Show preview, Autoplay and Preconnect first: with those settings on, the components contact YouTube or Vimeo as soon as the page loads.

Element state

Every managed element gets data-cmp-state="granted" or "denied", which you can use for styling.

Consent Gates

A Consent Gate lets visitors allow a single service right where its content appears. Gates have two modes.

Placeholder mode (default)

The content stays hidden behind a designed placeholder until the visitor allows the service. Use it for HTML embeds such as maps, social posts and widgets.

Structure

<div data-cmp-gate="google-maps">                 <!-- consent-gate -->
<div data-cmp-gate-notice> <!-- visible until consent -->
<p>Google Maps</p>
<button data-cmp-action="accept-once">Load content</button>
<button data-cmp-action="accept-always" data-cmp-if="confirmed">Always allow Google Maps</button>
<button data-cmp-action="open-modal">Privacy settings</button>
</div>
<div data-cmp-gate-content> <!-- HTML Embed with a template -->
<template data-cmp-service="google-maps">…</template>
</div>
</div>

Interaction mode

The content stays visible and works like a normal component until someone interacts with it. The first click inside data-cmp-gate-content is held back and the notice appears on top. After Load content or Always allow, the original click continues automatically, so a video starts playing right away.

Structure

<div data-cmp-gate="youtube" data-cmp-gate-mode="interaction">   <!-- consent-gate -->
<div data-cmp-gate-notice> <!-- consent-gate-notice + is-consent-gate-overlay -->
<p>YouTube video</p>
<button data-cmp-action="accept-once">Load content</button>
<button data-cmp-action="accept-always" data-cmp-if="confirmed">Always allow YouTube</button>
<button data-cmp-action="dismiss">Cancel</button>
<button data-cmp-action="open-modal">Privacy settings</button>
</div>
YouTube component with data-cmp-gate-content <!-- consent-video -->
</div>
  • Focus moves into the notice when it opens. Cancel (dismiss) or Escape closes it and returns focus to the element that was clicked.
  • While the notice is open, the gate has data-cmp-requested and grows to at least 300 px (400 px on phones), so the notice never gets cut off.
  • Visitors who already allowed the service interact with the content directly.
  • If consent is revoked while a native player is loaded, the engine stops it (about:blank). It can be played again after the next page load.
  • Interaction mode works for anything that only loads on click, for example your own Load map button.

Webstudio’s YouTube and Vimeo components

Put the component inside an interaction-mode gate, add data-cmp-gate-content to it in Settings → Attributes, and use these settings:

SettingYouTubeVimeoWhy
Show previewOffOffOn loads the thumbnail from img.youtube.com, or calls vimeo.com/api and loads from vimeocdn.com.
AutoplayOffOffOn loads the player immediately.
PreconnectOff–On opens a connection to YouTube on page load.
Privacy enhanced modeOn–Uses youtube-nocookie.com once the player loads.
Do not track–OnAsks Vimeo not to track the session.
Preview ImageYour own uploadYour own uploadSelf-hosted thumbnails need no consent.

The generator copies ready-made YouTube and Vimeo gates with these settings and your video URL. The tests confirm that no request reaches YouTube, Vimeo or their image servers before consent.

Accept once and always

  • Load content (accept-once) grants consent for the current page view only; nothing is stored.
  • Always allow (accept-always) stores consent for this service. It is only offered after the visitor made a first decision, so a single click in a gate never counts as a decision about all other services.
  • Buttons outside a gate can target a service with data-cmp-name="youtube".

Attribute reference

Actions

Value of data-cmp-actionEffect
accept-allGrant all services (except contextualOnly), save and close.
decline-allDeny all non-required services, save and close.
saveSave the current switch positions and close.
open-modalOpen the preferences modal. Works on any element on any page.
closeClose the modal. Unsaved switch changes are discarded for returning visitors. Ignored when mustConsent requires a decision.
accept-onceAllow the service of the closest gate for this page view.
accept-alwaysAllow and store the service of the closest gate.
dismissClose an interaction-mode gate notice without deciding.
resetDelete the stored decision and show the notice again.

Structure and bindings

AttributeUsed onPurpose
data-cmp-noticeNotice regionShown while the notice is open.
data-cmp-modalModal wrapperShown while the preferences modal is open.
data-cmp-dialogDialog elementReceives focus; Tab is trapped inside.
data-cmp-toggleCheckboxservice:<name>, purpose:<id> or all.
data-cmp-purposePurpose rowGroups service rows for purpose switches and badges.
data-cmp-service-itemService rowConnects a translated row to a service.
data-cmp-service-defRegistry itemTechnical service definition (rendered from consentServices).
data-cmp-serviceScript, template, link, iframe…Blocked until the service is granted.
data-cmp-onScriptaccept (default) or decline.
data-cmp-gateGate wrapperService name of a Consent Gate.
data-cmp-gate-modeGate wrapperinteraction: keep the content visible and hold back the first click until consent.
data-cmp-gate-notice / data-cmp-gate-contentGate childrenNotice and gated content.
data-cmp-requestedGate wrapper (set by the engine)An interaction-mode notice is open.
data-cmp-statusAny elementLive status of a service; sets data-cmp-state.
data-cmp-langAny elementOnly shown when it matches the page language.
data-cmp-previewDesign framenotice or modal: shows the fixed UI inline for designing.

Conditional visibility

data-cmp-ifVisible when
confirmed / unconfirmedThe visitor has (not) made a decision.
changedThe service list changed since the stored decision.
required / not-requiredThe closest service or purpose is (not) required.
opt-outThe closest service is opt-out.
granted / deniedThe closest service, status or gate is (not) active.

State on <html>

AttributeValues
data-cmploading until the page is parsed, then ready.
data-cmp-opennotice or modal while one is open.
data-cmp-confirmedtrue or false.
data-cmp-changedPresent when services changed.
data-cmp-confirmingPresent during the confirm delay.
data-cmp-languageResolved language, e.g. de.

JavaScript API & events

JavaScript

cmp.show();                          // open the preferences modal
cmp.showNotice(); cmp.hide();
cmp.getConsent("youtube"); // effective consent: true / false
cmp.getConsents(); // { "google-analytics": true, … }
cmp.isConfirmed(); // visitor has decided
cmp.getConsentId(); // "c7f3aa11-…", the ID stored with the decision
cmp.getServices(); // parsed service definitions
cmp.getLanguage(); // "en"
cmp.setConsent("youtube", true); // change and save (pass false as 3rd argument to skip saving)
cmp.acceptAll(); cmp.declineAll(); cmp.save(); cmp.reset();
cmp.refresh(); // re-sync after custom DOM changes

const off = cmp.on("save", ({ type, consents, changes }) => {});
document.addEventListener("cmp:service", (event) => console.log(event.detail));
EventDetailFires when
readyconsentsService definitions were read after the first page load.
changeconsentsA switch changed (not yet saved).
save{ type, consents, changes }A decision was stored. type is accept, decline, save, contextual-accept or api.
service{ name, consent, service }A service’s effective consent changed.
init{ service }A service was seen for the first time.
modal{ open }The preferences modal opened or closed.
gate{ name, requested }An interaction-mode gate held back a click and opened its notice.

Every event is also dispatched on document as cmp:<event>.

Design & Craft tokens

Every consent token reads a namespaced set of **--cmp-* variables** on Global Root. Restyle the whole consent UI there, or edit a single token in the Style panel. Each variable defaults to the matching Craft variable when your project has one (e.g. --cmp-accent: var(--background-accent, #1d4ed8)), so Craft projects match automatically. In any other project, point them at your own variables.

Theme variables

VariableDefaultUsed for
--cmp-backgroundvar(--background-primary, #ffffff)Notice, dialog and gate background
--cmp-surfacevar(--background-secondary, #f3f4f6)Purpose and service rows, gate placeholder, button hover base
--cmp-textvar(--foreground-primary, #15171c)Text
--cmp-text-mutedvar(--foreground-secondary, #4d5461)Descriptions and secondary text
--cmp-bordervar(--border-default, #dde0e5)Dividers and badges
--cmp-controlvar(--border-control, #6f7582)Switch track when off, outlined button border
--cmp-accentvar(--background-accent, #1d4ed8)Primary button, switch when on, links
--cmp-on-accentvar(--foreground-on-accent, #ffffff)Text on the primary button
--cmp-focusvar(--border-focus, var(--cmp-accent))Focus ring
--cmp-warningvar(--foreground-warning, #9a4a00)“Services changed” note
--cmp-disabledvar(--foreground-disabled, var(--cmp-text-muted))Disabled text
--cmp-inversevar(--background-inverse, var(--cmp-text))Video placeholder background
--cmp-scrimvar(--overlay-scrim, color-mix(in srgb, var(--cmp-text) 55%, transparent))Backdrop behind the dialog
--cmp-hovervar(--overlay-interaction-hover, color-mix(in srgb, var(--cmp-text) 6%, transparent))Hover tint on buttons
--cmp-pressedvar(--overlay-interaction-pressed, color-mix(in srgb, var(--cmp-text) 12%, transparent))Pressed tint on buttons
--cmp-on-accent-hovervar(--overlay-on-accent-hover, color-mix(in srgb, var(--cmp-on-accent) 14%, transparent))Hover tint on the primary button
--cmp-on-accent-pressedvar(--overlay-on-accent-pressed, color-mix(in srgb, var(--cmp-on-accent) 24%, transparent))Pressed tint on the primary button
--cmp-radiusvar(--radius-default, 16px)Notice, dialog and gate corners
--cmp-radius-smallvar(--radius-small, 10px)Small corners (rows, placeholders)
--cmp-radius-fullvar(--radius-full, 999px)Switches, badges and the close button
--cmp-button-radiusvar(--cmp-radius-full)Button corners (set 0 for square buttons, switches keep --cmp-radius-full)
--cmp-button-border-width1pxButton border width
--cmp-shadowvar(--shadow-overlay, 0 24px 64px -12px rgb(0 0 0 / 0.28))Notice and dialog shadow
--cmp-heading-fontinheritFont of titles and purpose/service labels (inherit = page font)
--cmp-heading-weight600Weight of titles and labels
--cmp-heading-transformnoneLetter case of titles and labels, e.g. uppercase
--cmp-heading-letter-spacingnormalLetter spacing of titles and labels
--cmp-button-fontinheritButton font
--cmp-button-weight600Button weight
--cmp-button-transformnoneButton letter case
--cmp-button-letter-spacingnormalButton letter spacing
--cmp-gap-xsvar(--gap-xs, 4px)Spacing
--cmp-gap-svar(--gap-s, 8px)Spacing
--cmp-gap-mvar(--gap-m, 16px)Spacing
--cmp-gap-lvar(--gap-l, 24px)Spacing
--cmp-spacingvar(--spacing-default, 24px)Inner padding of notice and dialog
--cmp-focus-widthvar(--focus-width, 2px)Focus ring width
--cmp-focus-offsetvar(--focus-offset, 2px)Focus ring offset
--cmp-durationvar(--duration-default, 180ms)Transition duration
--cmp-easingvar(--easing-default, cubic-bezier(0.2, 0, 0, 1))Transition easing
--cmp-layervar(--layer-overlay, 2147483000)z-index of notice and dialog

Tokens are named consent-* and variant tokens is-consent-* (Craft modifiers, always combined with their base token). When you restyle tokens directly, include both prefixes: the button borders and colors live in is-consent-button-primary and is-consent-button-secondary.

Composite tokens

BlockElements and variants
consent-noticeconsent-notice-body, consent-notice-title, consent-notice-text, consent-notice-changes, consent-notice-actions
consent-modalconsent-modal-scrim, consent-modal-dialog, consent-modal-header, consent-modal-title, consent-modal-close, consent-modal-text, consent-modal-body, consent-modal-footer
consent-purposesconsent-purpose, is-consent-purpose-all, consent-purpose-header, consent-purpose-label, consent-purpose-description, consent-purpose-services, consent-purpose-summary
consent-servicesconsent-service, consent-service-header, consent-service-label, consent-service-description
consent-buttonis-consent-button-primary, is-consent-button-secondary, is-consent-button-ghost
consent-switchStates: :checked, :indeterminate, :disabled, :focus-visible, ::before (thumb)
consent-gateconsent-gate-notice, consent-gate-title, consent-gate-text, consent-gate-actions, consent-gate-content
consent-statusconsent-status-label, is-consent-status-label-granted
Othersconsent, consent-language, consent-link, consent-badge, consent-preview, is-consent-preview-modal

Designing in the Builder

Custom Code doesn’t run in the Builder, so the engine is missing there: the fixed notice and preferences dialog stay hidden and only the first language is shown. To edit them, select the Consent Manager root, open the Data panel and set the Builder preview variables:

VariableValuesEffect in the Builder
canvasPreviewoff, notice, modal, hideShows the notice or the preferences dialog on the canvas, on every page with the Consent Manager Slot. With off, a small hint in the corner of the canvas points to this variable; hide removes the hint.
canvasLanguageempty or a language code, e.g. deShows that translation instead of the first one, including data-cmp-lang labels elsewhere on the page.

Select elements on the canvas or in the Navigator and edit texts in consentTranslations, styles in the consent-* tokens. The flags only act while the engine is absent, so the published site is unaffected even if you forget to switch them back to off. Gates always show both their notice and content in the Builder.

Accessibility

  • Default color pairs meet WCAG 2.2 AA: body text ≥ 6.8:1, accent buttons 7.1:1, switch tracks ≥ 3.7:1 against their backgrounds.
  • The modal is a role="dialog" with aria-modal, labelled by its title and described by its text. Focus moves into it, Tab is trapped, Escape closes it and focus returns to the opener.
  • Switches are native checkboxes with role="switch"; purpose switches expose a mixed state. Every switch has a visible label and a description.
  • Required and opt-out states are communicated with text badges, not color alone. Focus rings use --border-focus.
  • The notice is a labelled region that doesn’t steal focus, so keyboard and screen reader users can keep reading the page.

Automated audits may report that role="switch" needs aria-checked. For native checkboxes the checked state is exposed by the browser, and adding a static aria-checked would be wrong.

Troubleshooting

SymptomCheck
The notice never appearsIs the CMP snippet in Custom Code and is the Consent Manager Slot on the page? Was a decision already stored? Run cmp.reset().
A script doesn’t run after consentDoes data-cmp-service exactly match a name in consentServices? Is the original type text/plain? Check document.head for a script with data-cmp-for.
A script runs before consentThe original tag must not have a JavaScript type, and the URL must be in data-src, not src.
An embed appears twice or stays emptyUse a <template> inside an HTML Embed rather than an iframe with data-src next to other markup.
Tracking cookies remain after decliningCompare cookie names with the cookies patterns. Cookies on other domains or HttpOnly cookies can’t be deleted by JavaScript.
Wrong languageCheck Page Settings → Language and cmp.getLanguage(); add a matching entry to consentTranslations.
A native video contacts YouTube or Vimeo before consentTurn off Show preview, Autoplay and Preconnect on the component, and check that it has data-cmp-gate-content inside a gate with data-cmp-gate-mode="interaction".
A right-to-left language shows left-to-rightAdd "dir": "rtl" to its entry, or use a language code from the right-to-left list.
The notice reopens for returning visitorsThe service list changed. This is intentional: new services need a new decision.
Want to debugSet debug: true in cmpConfig and watch the console.

Migrating from other consent managers

  • Remove the old consent manager’s script and its styles from Custom Code.
  • Recreate your services in consentServices and your copy in consentTranslations.
  • Replace attributes on blocked elements: data-name="x" → data-cmp-service="x". type="text/plain", data-src, data-href and data-type work as before.
  • Replace show() calls with cmp.show() and callbacks with cmp.on("service", …).
  • Use a new storageName if the old manager used the same cookie name, so visitors are asked once with the new UI.

We use cookies and similar technologies for essential functions and, with your consent, for analytics, marketing and embedded media. You can change your choice at any time. Learn more in our privacy policy.

Our services have changed since your last visit. Please review your choice.

Wir verwenden Cookies und ähnliche Technologien für notwendige Funktionen und, mit Ihrer Einwilligung, für Statistik, Marketing und eingebettete Medien. Sie können Ihre Auswahl jederzeit ändern. Mehr dazu in unserer Datenschutzerklärung.

Unsere Dienste haben sich seit Ihrem letzten Besuch geändert. Bitte prüfen Sie Ihre Auswahl.

Usamos cookies y tecnologías similares para funciones esenciales y, con tu consentimiento, para analítica, marketing y contenido incrustado. Puedes cambiar tu elección en cualquier momento. Más información en nuestra política de privacidad.

Nuestros servicios han cambiado desde tu última visita. Revisa tu elección.

نستخدم ملفات تعريف الارتباط والتقنيات المشابهة للوظائف الأساسية، وبموافقتك للإحصاءات والتسويق والمحتوى المضمّن. يمكنك تغيير اختيارك في أي وقت. لمعرفة المزيد، اطّلع على سياسة الخصوصية.

تغيّرت خدماتنا منذ زيارتك الأخيرة. يُرجى مراجعة اختيارك.