Many teams expect their CMP (Axeptio, Didomi, OneTrust, Cookiebot…) to push one “consent dataLayer” that every tag manager understands. That object doesn’t exist. Each analytics or ads library reads consent through its own API, and some of them can also read the IAB TCF string directly. The useful question is not “does my tag manager read TCF?” but “what does each tag read, and who sets it?”
1. What a CMP does
A CMP shows the banner, stores the visitor’s choice, and exposes it. Depending on the CMP and its settings, it exposes it through:
- the IAB TCF API (
__tcfapi) and its TC string; - its own JavaScript API and events;
- direct calls to vendor consent APIs, for example Google’s consent mode, often through a Tag Manager template.
TCF is a standardised way to record and share consent choices. Using it does not make a site GDPR-compliant by itself.
2. Google tags: consent mode, or TCF
Consent mode. The page sets a default before any Google tag sends data, then the CMP updates it when the visitor chooses. Google: “The order of the code here is vital. If your consent code is called out of order, consent defaults won’t work.”
// 1. Before any measurement command, on every page
gtag('consent', 'default', {
'ad_storage': 'denied',
'ad_user_data': 'denied',
'ad_personalization': 'denied',
'analytics_storage': 'denied'
});
// 2. When the visitor makes a choice (usually done by the CMP)
gtag('consent', 'update', {
'ad_storage': 'granted',
'ad_user_data': 'granted',
'ad_personalization': 'granted',
'analytics_storage': 'granted'
});
A denied default is the intended setup, not an error. ad_user_data and ad_personalization were added in consent mode v2. In Google Tag Manager, Google recommends letting a CMP handle the updates; many CMPs publish a Community Template that sets both the default and the update.
TCF. Google tags can also read the TC string natively. Enable it with window['gtag_enable_tcf_support'] = true on the site, or with enableAdvertiserConsentMode: true in the CMP’s TCData. The Google tag then maps TCF purposes to consent mode:
| TCF purpose denied | Effect |
|---|---|
| Purpose 1 | ad_storage and ad_user_data denied |
| Purpose 3 or 4 | ad_personalization denied |
| Purpose 7 | ad_user_data denied |
| Purpose 9 or 10 | Google signals disabled in GA4 (web) |
If the CMP doesn’t respond within 500 milliseconds, the tag uses the default consent settings.
3. Adobe: two paths, depending on the library
Legacy AppMeasurement and ECID: the Opt-In Service. The categories are fixed:
adobe.OptInCategories = {
"AAM": "aam",
"ANALYTICS": "aa",
"ECID": "ecid",
"TARGET": "target"
}
adobe.optIn.approve(['aa', 'ecid']);
adobe.optIn.deny(['target']);
Note the analytics category is aa, not analytics. If you pass shouldWaitForComplete = true, nothing is applied until you call adobe.optIn.complete().
Web SDK (alloy): setConsent. It accepts Adobe’s own standard (1.0 or 2.0) or an IAB TCF string:
alloy("setConsent", {
consent: [{
"standard": "IAB TCF",
"version": "2.0",
"value": tcString, // from __tcfapi
"gdprApplies": true
}]
});
// or, with Adobe's standard 1.0
alloy("setConsent", {
consent: [{ "standard": "Adobe", "version": "1.0", "value": { "general": "in" } }]
});
The tag manager itself is Adobe Experience Platform Tags (formerly Launch). It deploys either library; the consent path depends on which one you use.
4. Matomo: one API, two modes
Matomo’s consent guide documents its own _paq API. Pick one mode, and use the matching calls:
| Mode | Before consent | Give / remember | Withdraw |
|---|---|---|---|
requireConsent |
No tracking request, no cookie | rememberConsentGiven |
forgetConsentGiven |
requireCookieConsent |
Requests sent, no cookie | rememberCookieConsentGiven |
forgetCookieConsentGiven |
5. Summary
| Library | Reads the TC string? | Consent API |
|---|---|---|
| Google tag (GA4, Ads, Floodlight) | Yes, once TCF support is enabled | gtag('consent', 'default' / 'update', …) |
| Adobe AppMeasurement + ECID | No | adobe.optIn.approve / deny (aa, ecid, target, aam) |
| Adobe Web SDK | Yes, passed to setConsent |
alloy("setConsent", …) |
| Matomo | Not in its consent guide | _paq consent calls |
6. When you need a mapping script
If your CMP already sets Google consent mode (or you enabled TCF support) and you use the Adobe Web SDK with the TC string, there may be little to map. For legacy Adobe and for Matomo, you usually need a small script that listens to the CMP and calls the right API:
// cmpConsent: whatever your CMP exposes (callback, event, TCF purposes...)
function applyConsent(cmpConsent) {
if (cmpConsent.analytics) {
adobe.optIn.approve(['aa', 'ecid']);
_paq.push(['rememberConsentGiven']);
} else {
adobe.optIn.deny(['aa', 'ecid']);
_paq.push(['forgetConsentGiven']);
}
}
Always check what your CMP actually sends, in Tag Assistant for Google and in the browser console for the others, before writing any mapping.
7. Common mistakes
- No consent default, or a default set after the Google tag. Google tags can’t apply consent correctly.
- Assuming every tag reads the same signal. A CMP template that sets Google consent mode does nothing for Adobe Opt-In or Matomo.
- Wrong Adobe category names.
analyticsis not a valid Opt-In category; useaa. - Mixing Matomo modes.
requireConsentwithrememberCookieConsentGivendoesn’t do what you expect. - Forgetting withdrawal. Google: update to denied. Adobe Opt-In:
deny. Matomo:forgetConsentGivenorforgetCookieConsentGiven.
Related reading
- “Cookieless”: Marketing Promise vs Technical Reality – A Deep Technical Dive
- Beyond Cookies: The Complete Map of Browser Tracking Signals (and Documented Use Cases)
- Safari 27 Blocks Adtech Domains at the Network Layer: What the WebKit Source Says, What I Measured, and How to Audit Your Site