consent-mode-v2-adapter
v0.1.0
Published
Tiny wiring helper for Google Consent Mode v2: default-denied gtag with EEA region filter, granular update from your banner of choice. Works with vanilla-cookieconsent, Klaro, Cookiebot, custom UI, or no UI at all. Apache 2.0.
Downloads
126
Maintainers
Readme
consent-mode-v2-adapter
Tiny wiring helper for Google Consent Mode v2: default-denied gtag with EEA region filter, granular update from your banner of choice. Works with vanilla-cookieconsent, Klaro, Cookiebot CMP, custom UI, or no UI at all (e.g. server-rendered preferences page).
Banner-agnostic. Pure data + 4 functions. No DOM, no CSS, no a11y burden.
Apache 2.0. ~250 LOC. Zero required dependencies.
Why this exists
Google made Consent Mode v2 mandatory for AdSense + Ads measurement in March 2024. The contract is two-step:
- Push
gtag('consent', 'default', { ad_storage: 'denied', ... })before any tag fires. - Push
gtag('consent', 'update', { ... })with granular state when the user accepts.
Most cookie banner libraries handle step 0 (the UI) but skip the wiring. This package does only the wiring. Pair it with the banner you already use, or call directly from a preferences form.
60-second wiring
With any banner library (vanilla pattern)
npm install consent-mode-v2-adapterimport { setDefaultConsent, updateConsent } from 'consent-mode-v2-adapter';
// On page load, before GTM/GA4 fires any tag:
setDefaultConsent();
// When the user accepts categories (from your banner's onAccept callback,
// or from a preferences form submit):
updateConsent({
analytics: true, // grants analytics_storage
marketing: true, // grants ad_storage + ad_user_data + ad_personalization
functionality: false, // denies functionality_storage
personalization: false, // denies personalization_storage
});That's it. Default state is denied for the 6 user-driven *_storage signals (security_storage stays granted per Google policy). EEA + UK + EFTA region filter applied by default; pass null to apply globally.
With vanilla-cookieconsent (orestbida)
npm install consent-mode-v2-adapter vanilla-cookieconsentimport * as CookieConsent from 'vanilla-cookieconsent';
import 'vanilla-cookieconsent/dist/cookieconsent.css';
import { setDefaultConsent, defaultCategories, translations } from 'consent-mode-v2-adapter';
import { wireVanillaCookieConsent } from 'consent-mode-v2-adapter/adapters/vanilla-cookieconsent';
setDefaultConsent();
const update = () => wireVanillaCookieConsent(CookieConsent);
CookieConsent.run({
categories: defaultCategories,
language: { default: 'it', translations },
onConsent: update,
onChange: update,
});defaultCategories ships GDPR-aligned 4-category preset (necessary, analytics, marketing, preferences) with autoClear patterns for GA4 (_ga*, _gid), Google Ads (_gcl_*), Meta (_fbp, _fbc, IDE). Override per stack as needed.
translations.it and translations.en provide ready text for the consent + preferences modals.
With Klaro / Cookiebot CMP / custom UI
Same shape: call setDefaultConsent() on load, call updateConsent({ analytics, marketing, ... }) when your banner reports the user's choice. The library doesn't care which banner emitted the event.
Public API
import {
setDefaultConsent,
updateConsent,
buildConsentUpdatePayload,
EEA_REGIONS,
defaultCategories,
buildCategories,
translations,
} from 'consent-mode-v2-adapter';| Export | Purpose |
|---|---|
| setDefaultConsent({ regions?, waitForUpdate? }) | Push gtag('consent','default', ...). Call once on page load before GTM. |
| updateConsent({ analytics, marketing, functionality, personalization }) | Push gtag('consent','update', ...) with granular state. |
| buildConsentUpdatePayload(accepted) | Pure function; build the payload without pushing. Useful for server-rendered preferences pages that need to emit the same shape elsewhere. |
| EEA_REGIONS | string[] of 32 ISO codes (EU + UK + Switzerland + EFTA). Default region filter for setDefaultConsent. |
| defaultCategories | GDPR-aligned 4-category preset (data only). |
| buildCategories(overrides) | Merge overrides onto the preset. |
| translations | { en: {...}, it: {...} } ready text packs. |
Adapter subpath:
import { wireVanillaCookieConsent } from 'consent-mode-v2-adapter/adapters/vanilla-cookieconsent';What this is NOT
- Not a cookie banner. Bring your own UI.
- Not a CMP. No IAB TCF v2.2 signal. Use vanilla-cookieconsent's IAB plugin alongside if you need TCF.
- Not opinionated about your tracker. No GTM/GA4 IDs in the package. Configure your own container.
- Not a fork of vanilla-cookieconsent. The adapter is a 60-LOC bridge to its API; install it as a peer dep if you use the bridge.
Templates (compliance copy)
Pre-written GDPR + ePrivacy text in templates/:
cookie-policy-it.md| Italian cookie notice (Garante 2021 aligned), placeholder-drivencookie-policy-en.md| English cookie notice (GDPR + ePrivacy)privacy-policy-snippet-it.md| Cookie section to paste into existing privacy policyprivacy-policy-snippet-en.md| same in English
Always validate with privacy counsel for your specific case.
Region filter
Default behavior of setDefaultConsent(): deny all *_storage signals only for traffic from EEA + UK + Switzerland + EFTA (32 ISO codes in EEA_REGIONS). Non-EU traffic falls back to whatever defaults your tag server-side has configured. This avoids breaking attribution for global campaigns where consent rules differ.
// Default: EEA-only denial
setDefaultConsent();
// Apply globally (no region filter)
setDefaultConsent({ regions: null });
// Custom subset (e.g. US states with consent laws)
setDefaultConsent({ regions: ['CA', 'CO', 'CT', 'VA'] });gtag stub for delayed-load GTM
If window.gtag is not defined when setDefaultConsent() runs (common when GTM is loaded after first user interaction to keep it off the LCP critical path), the library installs a tiny stub that pushes args onto window.dataLayer. The real gtag drains the queue on load, so consent signals are replayed in order. No special configuration needed.
Maintenance scope
Single-maintainer secondary asset, scoped intentionally. See SECURITY.md for vulnerability disclosure and CONTRIBUTING.md for PR process + commit-message contract.
License
Apache License 2.0. See NOTICE for third-party attributions (only the optional vanilla-cookieconsent adapter; the core library has zero runtime deps).
