This guide shows you how to set up GTM Kit so it works with a Consent Management Platform (CMP) without double-firing or conflicting consent state.
The two-rule summary
Two simple rules cover almost every CMP integration:
- Decide who owns Consent Mode v2. Either GTM Kit emits the defaults, or your CMP does. Never both.
- Decide who loads the GTM container. Either GTM Kit injects it, or your CMP holds it back until consent. Never both.
If you get those two rules right, everything else falls into place.
Common CMPs and the right setup
The recommended configuration for the four CMPs most commonly used with GTM Kit:
Cookiebot
Cookiebot emits Consent Mode v2 defaults itself when you enable Google Consent Mode in its settings. It also blocks scripts by attribute (data-cookieconsent="ignore").
- GTM Kit, Default Consent State: Off.
- GTM Kit, Inject Container Code: keep on. Cookiebot does not block GTM, and from 2.10 GTM Kit adds
data-cookieconsent="ignore"to its helper scripts itself so Cookiebot’s auto-blocking lets them through. Individual tags are still gated by Consent Mode. - In Cookiebot: enable Google Consent Mode in the dashboard.
Complianz
Complianz integrates with the WordPress Consent API and emits Consent Mode v2 defaults itself.
- GTM Kit, Default Consent State: Off.
- GTM Kit, Inject Container Code: keep on. Complianz reads consent state from the user’s choices and signals tags via Consent Mode.
- In Complianz: confirm Google Consent Mode v2 is enabled under Integrations.
CookieYes
CookieYes emits Consent Mode v2 defaults when configured.
- GTM Kit, Default Consent State: Off.
- GTM Kit, Inject Container Code: keep on.
- In CookieYes: enable Google Consent Mode in Settings, Advanced.
Cookie Information (Danish CMP)
Cookie Information emits Consent Mode v2 defaults.
- GTM Kit, Default Consent State: Off.
- GTM Kit, Inject Container Code: keep on.
- In Cookie Information: confirm Google Consent Mode is enabled in the platform.
CMP script attributes
When a CMP plugin scans your page and adds data-cookieconsent="ignore" (Cookiebot), data-cmp-ab="1" (Iubenda), or data-cookie-consent="ignore" (CookieYes) to scripts it doesn’t recognise, those scripts are gated until consent is given. GTM Kit’s helper scripts shouldn’t be gated; they only push to window.dataLayer, they don’t set cookies or send data anywhere themselves.
Settings → Consent → CMP script attributes lets you tell GTM Kit to add the right ignore attribute itself, so the CMP’s scanner sees it and lets the scripts through.
- Cookiebot. Adds
data-cookieconsent="ignore". - Iubenda. Adds
data-cmp-ab="1". - CookieYes. Adds
data-cookie-consent="ignore". - Custom. Add a custom attribute name and value for any other CMP. Names accept letters, digits, underscores, and hyphens. Other characters are stripped at save.
On fresh installs we detect Cookiebot, Iubenda, or CookieYes and pre-select the matching toggle. Upgraders from pre-2.10 keep Cookiebot on by default so the previously hardcoded data-cookieconsent="ignore" attribute is preserved.
Why “off” is the right answer for all four
All four CMPs above emit gtag('consent', 'default', ...) themselves. If GTM Kit also emits a default block, the second one overrides the first depending on script load order. The override is unpredictable across browsers and visit conditions, which means consent state silently varies for some visitors.
The fix is to let only one source declare defaults. Your CMP is the better choice because it knows the user’s region (it has IP geolocation), the user’s stored preference (cookie history), and the legal text shown in the banner. GTM Kit only knows what is in the settings page.
When you should turn GTM Kit’s Consent Mode on
Enable Default Consent State in GTM Kit only if your CMP does not emit Consent Mode v2 defaults. Reasons this happens:
- The CMP is older and only supports v1.
- The CMP supports v2 but your subscription tier does not include it.
- You are using a homegrown consent banner or a basic plugin that just sets cookies.
In those cases, GTM Kit’s defaults are the only ones present and the master toggle should be on.
Container injection: who loads GTM?
The default for both GTM Kit and most CMPs is “I load the container.” Both being on means the container loads twice. Pick one.
The answer depends on whether your CMP is “blocking before consent” or “permissive.”
Blocking CMPs (some Cookiebot tiers, some OneTrust modes): the CMP wants to hold the GTM script until consent is given. In those cases:
- GTM Kit, Inject Container Code: Off.
- The CMP loads the snippet itself, after consent.
Permissive CMPs (the recommended default for Cookiebot, Complianz, CookieYes, Cookie Information): the GTM container loads on every page, but tags inside it check Consent Mode before firing.
- GTM Kit, Inject Container Code: On.
- The CMP signals consent state via
gtag('consent', 'update', ...)and individual tags decide whether to fire.
The permissive approach is what Google’s own documentation recommends and what most CMPs default to. Tags that need consent skip silently; tags that do not need consent (e.g. session security) fire on every load.
Verify the setup works
In a fresh incognito window:
- Open your site. View source.
- There should be exactly one
gtag('consent', 'default', ...)block. If you see two, both GTM Kit and the CMP are emitting; turn one off. - The GTM container
<script>should appear once. If you see two, both GTM Kit and the CMP are injecting; turn one off. - The DevTools console should show no errors related to
gtag,dataLayer, orCookiebot/Complianz/cmp.
Click “Reject all” in the CMP banner and confirm Google tags do not fire (use GTM Tag Assistant). Click “Accept all” and confirm tags now fire.
Common issues
Cookiebot blocks GTM Kit’s data layer pushes. Cookiebot scans scripts and can prefix them with data-cookieconsent="ignore". If GTM Kit’s helper scripts (dataLayer, integrations) are scanned and gated, events stop pushing. Add an exception in Cookiebot, or in GTM Kit, go to Settings → Consent → CMP script attributes and turn on Cookiebot. This adds data-cookieconsent="ignore" to GTM Kit’s helper scripts so Cookiebot’s auto-blocking lets them through.
Two default blocks load and tags behave differently in different browsers. Classic symptom of dual emission. Audit and remove one.
The CMP banner shows but Consent Mode is never updated. The CMP is misconfigured. Open its settings and confirm “Google Consent Mode” is enabled. Check the CMP’s documentation for the specific toggle; the wording varies.
For CMPs we don’t support yet: register a signal source
When your CMP isn’t in the list above, you can teach GTM Kit to read consent from it directly by registering a signal source. The registered source takes over from the option-backed default, so you don’t have to flip the master toggle off.
Sources register with a priority. Higher priority wins. The reserved tiers are:
gtmkit_defaultat priority 10: the option-backed fallback.- Named CMP integrations at priority 80.
wp_consent_apiat priority 100.
To override the default, register at priority above 10. To sit below a named tier, pick a priority below it.
add_filter(
'gtmkit_consent_signal_sources',
static function ( array $sources ): array {
$sources['my_cmp'] = [
'id' => 'my_cmp',
'priority' => 90,
'is_active' => static fn(): bool => function_exists( 'my_cmp_is_loaded' )
&& my_cmp_is_loaded(),
'read' => static function (): array {
$cmp = my_cmp_get_state();
return [
'analytics_storage' => $cmp['stats'] ? 'granted' : 'denied',
'ad_storage' => $cmp['marketing'] ? 'granted' : 'denied',
// ... fill the remaining five categories.
];
},
];
return $sources;
}
);
read callables must return granted or denied for each of the seven Consent Mode v2 categories: ad_personalization, ad_storage, ad_user_data, analytics_storage, personalization_storage, functionality_storage, security_storage. Missing keys default to denied.