Google’s Consent Mode allows you to tailor how tags behave based on a user’s consent status for different tracking purposes. While primarily designed for use with Google tags, when used with Google Tag Manager (GTM), it can also help control third-party tags through Consent Mode’s APIs and custom logic.

There are two main types of Consent Mode:
- Advanced Consent Mode: Works automatically with Google’s services like GA4, Google Ads, and Floodlight. Tags adjust their behavior based on the user’s consent without needing major configuration changes.
- Basic Consent Mode (BCM): A manual and more complex setup where tags are prevented from firing until the user explicitly provides the necessary consent. This is the focus of our guide
Why Basic Consent Mode Is Challenging
Unlike Advanced Consent Mode, BCM requires a hands-on approach. Tags must be manually configured to remain dormant until the relevant consent is granted. This adds complexity, especially when dealing with asynchronous Consent Management Platforms (CMPs) or non-cooperative tools.
This guide will walk you through:
- Implementing Consent Mode (manually, with a CMP, or a hybrid approach).
- Configuring your tags in GTM to respect consent conditions….
Though the emphasis is on GTM, users of the standalone Google Tag can also benefit from many of the principles shared here.
What Is Basic Consent Mode?
BCM is not a specific feature—it’s an implementation pattern. It enforces that tags requiring consent must only trigger after consent is explicitly granted.
This aligns with data protection laws like GDPR and ePrivacy, which already demand such behavior. However, to enforce it with Consent Mode, your CMP must be integrated with Google’s Consent Mode API—or you’ll need to bridge that gap manually.
Consent Mode Calls: Default and Update
There are two key API calls in Consent Mode:
- Default: Should be called as early as possible, using the Consent Initialization – All Pages trigger. It defines the default consent states (typically all set to “denied”).
- Update: Called after the user’s consent status is known (either through user action or previously stored preferences). This call can occur multiple times per session.
Example – Default Call:
js
{
ad_storage: “denied”,
analytics_storage: “denied”,
ad_user_data: “denied”,
ad_personalization: “denied”
}
Example – Update Call:
js
{
ad_storage: “denied”,
analytics_storage: “granted”,
ad_user_data: “denied”,
ad_personalization: “denied”
}
The Ideal Setup
Step 1: Default Call
Always fire a tag using the Consent Initialization – All Pages trigger. Set all consent types to “denied”.
Step 2: Update Call
If the consent status is known (e.g., from cookies), fire an Update call immediately after the Default call using the same trigger. Follow this with a dataLayer.push() containing the current consent states, e.g.:
js
window.dataLayer.push({
event: ‘gtm_consent_update’,
analytics_storage: ‘granted’,
ad_storage: ‘denied’,
});
Step 3: User Interaction
When a user updates their consent choices, fire another Update call and push a new gtm_consent_update event.
Working with CMPs
While some CMPs offer dedicated GTM templates, many don’t support Consent Mode well or rely on asynchronous loading—leading to unpredictable tag behavior.
Best Practices:
- Load the CMP before GTM.
- Use GTM custom templates to manage Default and Update calls.
- Do not let the CMP directly control Consent Mode unless it’s designed to do so reliably.
Example: Cookiebanners.nl is a CMP that provides a GTM template integrating both Consent Mode and dataLayer events properly.
Manual Implementation with GTM Custom Templates
- Default Consent Tag
- Trigger: Consent Initialization – All Pages
- Set all states to “denied”
- Tag priority: 10
- Trigger: Consent Initialization – All Pages
- Update Consent Tag
- Same trigger
- Only fire if user consent is already known (read from cookies/localStorage)
- Set relevant states to “granted”
- Enable dataLayer.push() to trigger consent-based tags
- Same trigger
- Handling User Consent Changes
- When the user updates their settings, have the CMP push a gtm_consent_update event.
- Fire the Update tag again to reflect the new consent states.
- When the user updates their settings, have the CMP push a gtm_consent_update event.
Configuring Tags for Basic Consent Mode
Dealing with GTM’s “Once per page” Bug
Tags with “Once per page” enabled may not fire again after being blocked once. GTM mistakenly treats them as having already fired, even if blocked.
Fix: Control firing only through triggers, not Additional Consent Checks, for such tags.
Example Configurations
Initialization Tags (Fire Once per Page)
Use a trigger based on gtm_consent_update and relevant Data Layer variables like {{DLV – analytics_storage}} set to “granted”.
Tags that Fire Multiple Times
Set the trigger to fire on:
- gtm_consent_update (if consent is granted)
- Other triggers like virtual page views, scroll, login, etc.
Also, use Additional Consent Checks to ensure tags respect current consent.
Tags That Fire Under Specific Conditions
Use a Trigger Group that includes:
- A trigger for consent being granted (via gtm_consent_update)
- A trigger for a specific event (e.g., purchase)
This ensures tags like GA4 Purchase fire only when both conditions are met.
Edge Cases & Considerations
- Some CMPs delay consent availability—avoid relying solely on Update calls at page load.
- Prevent firing duplicate pageviews caused by simultaneous gtm_consent_update and virtual pageview events.
- Avoid CMPs that send conflicting Default or Update calls.
Final Thoughts
Setting up Basic Consent Mode is complex and often frustrating. The key challenge is ensuring that tags wait for consent while maintaining performance and data integrity.
While many CMPs are not optimized for this task, using GTM custom templates gives you full control. Ideally, the CMP should only inform GTM of the user’s choices. Let GTM handle the Consent Mode logic using stored values and dataLayer events.
A clean and proactive setup makes adapting tags to consent straightforward. But if you’re stuck with a limited CMP, you’ll need to get creative with triggers and variables.
Need help with a tricky use case or edge case? Drop a comment and share your situation—we’re here to help.
For more information, please follow this guide.