# CMP integration traps

The failures that come from how a consent management platform is wired in, with Cookiebot and OneTrust specifics. Checked against Cookiebot's developer and support pages and OneTrust's knowledge base on 2026-10-17. Cookiebot's help centre blocks non-browser clients, so open those pages in a browser at run time.

## Any CMP

- One writer per page. The CMP template in GTM, a hardcoded default in the theme, a CMS plugin and a second container each look valid alone and override each other together. Remove the redundant writer through the system that owns it, then rerun the full matrix.
- Read the configuration visitors actually receive. The CMP's script fetches its published configuration from the vendor CDN; find that request in the HAR and read it. It can differ from what the dashboard shows when a change was saved but not published, or when the page loads a different configuration ID.
- Category mapping is the contract. Write down which CMP category feeds each Google signal and each vendor tag, and test each mapping with a partial choice (C3, C4). A marketing category usually feeds all three ad signals.
- Banner region and Google region defaults are two settings. The CMP's geolocation decides which banner shows; the Google default decides the tag state before any update. Both must agree for every region in the specification, including the unknown-location fallback.
- Late banner. Causes seen in production:
  - The CMP script loads `async` or `defer`, or a performance plugin reorders scripts.
  - A CMS plugin or theme writes a Google tag before GTM loads.
  - Google tag gateway deployed by CDN injection controls load order, so Google tags can initialise before the CMP.
  - A returning visitor's stored choice is restored asynchronously, by a CMP running outside GTM or after a hardcoded tag, so the first tag sees the default.
- Ad blockers that stop GTM also stop a CMP loaded through GTM. Never test with one, and do not read "banner missing" in a blocked browser as a CMP fault.
- Scans are an inventory, not a test. Cookiebot's scanner does not submit forms or complete payments, so form and checkout tags are never exercised by it.
- Migration between CMPs: during cutover two banners or two writers can coexist, category IDs differ, and the old consent cookie stays on returning browsers. Test returning visitors who carry the old CMP's cookie.
- Implied consent. A CMP can record consent when the visitor scrolls, navigates or closes the banner (Cookiebot reports this as `Cookiebot.consent.method` `implied`; other CMPs have their own setting). Test it as C11. A grant without an explicit choice in an opt-in region is S1, reported to the privacy owner as a specification conflict.
- CMP fails to load. A blocked or slow CMP host must leave defaults denied, no optional tag sending, and the site usable. Test it as C14 with DevTools request blocking on the CMP host.
- IAB TCF switched on. Cookiebot and OneTrust often run with TCF enabled. Then a second consent channel exists next to consent mode:
  - Google tags read the TC string when the site sets `window['gtag_enable_tcf_support'] = true` or the CMP sets `enableAdvertiserConsentMode` in its TCData; Google maps TCF purposes to consent mode, and falls back to the defaults if the CMP does not answer within 500 ms.
  - Microsoft UET picks up TCF automatically.
  - Record per case the TCF fields on Ads requests (DV360 and Campaign Manager document them as `gdpr` and `gdpr_consent`; confirm the names in the HAR at run time) and the CMP's TC string state.
  - Check that the purpose and vendor consents agree with the consent mode state. A TC string that disagrees with `gcs` or `gcd` is a configuration-layer finding even when `gcs` reads `G111`, because it changes ad behaviour on its own.
  - Google's requirements for CMPs serving ads in the EEA, the UK and Switzerland are the vendor reference; read them live.

## Cookiebot

GTM deployment (Cookiebot support, updated July 2026):

- The "Cookiebot CMP" template from the Community Template Gallery, with the Domain Group ID in the "Cookiebot ID" field, on "Consent initialization - All pages". The site's domains must be registered in Cookiebot.
- The default is denied until consent. Region rows are added with "Add region"; several regions go in one comma-separated field, with ISO 3166-1 alpha-2 country codes and ISO 3166-2 subdivision codes. Cookiebot recommends always keeping a global row.
- Mapping: `ad_personalization`, `ad_storage` and `ad_user_data` to marketing; `analytics_storage` to statistics; `functionality_storage` and `personalization_storage` to preferences; `security_storage` to necessary.
- Tags with additional consent checks use a Custom Event trigger on `cookie_consent_update` in place of All Pages.
- Elements outside GTM (scripts, images, iframes in the template) need Cookiebot's prior-consent markup or they are not controlled.
- The template has an "Enable Google Consent Mode" checkbox; a direct script install can disable consent mode with `data-consentmode="disabled"`. Check neither is off by accident.

Verification specifics:

- The template registers defaults inside GTM and does not push them to the dataLayer. Cookiebot's check uses Tag Assistant's Consent tab ("On-page Defaults" must include `ad_user_data` and `ad_personalization`) and a console script that reads `google_tag_data.ics.entries`.
- On acceptance the dataLayer shows `cookie_consent_preferences`, `cookie_consent_statistics` and `cookie_consent_marketing` events for the accepted categories.
- JavaScript API: `Cookiebot.consent.necessary`, `.preferences`, `.statistics`, `.marketing`, `Cookiebot.consent.method` (`implied` or `explicit`), `Cookiebot.hasResponse`, `Cookiebot.regulations.gdprApplies`. Methods `Cookiebot.renew()` (reopen to change), `Cookiebot.withdraw()`, `Cookiebot.runScripts()` (for content loaded later, such as SPA routes). Events include `CookiebotOnConsentReady`, `CookiebotOnAccept` and `CookiebotOnDecline`.
- The `CookieConsent` cookie value `-1` means the visitor is outside a region that requires consent and all cookies are accepted.
- Cookiebot's Google Consent Mode checker (Cookiebot's "Google Consent Mode Checker" article): in the Cookiebot CMP Admin, "Domains and Aliases", select the domain, scroll to the "Google Consent Mode Check" section and select "Start GCM check". It checks that defaults are set, that the banner signals updates to the dataLayer, and whether non-essential Google trackers are set before consent. It works from what the browser and dataLayer show and does not grade each GTM tag's consent settings, so a clean result does not cover tag-level settings. Sites behind a login cannot be checked.
- The cookie scan report marks entries where "Blocked until accepted by user" is No. Menu labels change; confirm them live.

Automatic blocking (`data-blockingmode="auto"`):

- The Cookiebot script must load first, without `async` or `defer`, from `consent.cookiebot.com`. Anything loaded before it can set cookies.
- The blocker works from a checklist built by scans, published as a `configuration.js` file on Cookiebot's consent CDN under the domain group ID and domain. A 404 means the domain has not been scanned; Cookiebot says a 404 lasting more than 24 hours may mean the scanner cannot reach the site. Before the first scan only a built-in list of known trackers is blocked.
- A bundle that needs several categories loads only when all of them are granted. A site bundle mixing essential code and tracking breaks for rejecters; the fix is to separate the tracking, not to reclassify the bundle as necessary.
- Every resource from a third-party domain that sets cookies inherits that domain's category, including images.
- A 1x1 image with query parameters is treated as a pixel tracker.
- Unclassified trackers are not blocked before consent but are removed on each page load. Classify them.
- `data-cookieconsent="ignore"` exempts an element; Cookiebot advises switching to manual markup if more than three elements need ignoring.

## OneTrust

From OneTrust's knowledge base articles on Google Consent Mode, Cookie Consent integration with GTM and OneTrust cookies:

- Enable "Google Consent Mode" per rule in Cookie Consent, Geolocation Rules. Default mapping: Performance to `analytics_storage`; Targeting to `ad_storage`, `ad_user_data` and `ad_personalization`. Mappings are editable per rule.
- The v2 signals need script version 202311.1.0 or newer.
- The consent defaults (template or `gtag`) must match the Geolocation Rule mapping, with region-specific defaults for the other rules. The most specific region wins.
- GTM template: the OneTrust CMP template injects the banner script itself. OneTrust warns that two banner scripts on one page lead to unexpected behaviour, so remove the hardcoded banner when the template is used. Template setup: the Data Domain Script, "Do you want to use Google Consent Mode?" set to Yes, one "Add GCM Category" row per signal, trigger Consent Initialization - All Pages.
- Without the template, the order is: consent default, then the GTM or `gtag` snippet, then the OneTrust script.
- OneTrust states that Google Consent Mode is an alternative to script blocking: other vendors' tags still need additional consent checks in GTM.
- dataLayer: `OneTrustGroupsUpdated` fires on page load and on every consent change; `OptanonLoaded` and `OneTrustLoaded` confirm OneTrust reached the container. `OnetrustActiveGroups` is a comma-delimited list with leading and trailing commas, such as `,C0001,C0002,`. Match a category with the commas included. The variable name has a lowercase "t" in "Onetrust".
- Window events: `OneTrustGroupsUpdated` (load and change) and `OTConsentApplied` (after an explicit consent action and the consent receipt call). `OneTrust.OnConsentChanged` is a callback that runs earlier than `OTConsentApplied`.
- Cookies: `OptanonConsent` holds `groups=` pairs such as `C0001:1,C0002:0` (1 consented, 0 not); `OptanonAlertBoxClosed` records that the banner was answered. Both last one year by default, set by "Reconsent will occur after" in the geolocation rule. Category IDs beyond the examples are tenant-specific; read them from the tenant.
- OneTrust's developer site has an llms.txt and an API-spec MCP server; its `execute-request` tool can call live APIs, so use only the search and read tools without approval.

## Diagnosing a late banner from one HAR

1. Note the start time of the CMP script, the CMP configuration response, the first Consent event (Tag Assistant), the first Google request and the first non-Google vendor request.
2. Any vendor request before the CMP configuration response: follow its initiator chain to the script, theme file, plugin or CDN feature that sent it, and name its owner.
3. Repeat with throttling. If the order changes, it is a race: fix the dependency (load order, template trigger, gateway configuration). Do not add fixed delays to tags; they hide the race and lose data.
