Integrations
- Written for
- + Written for
- Deprecated
- + Deprecated
- Applies to
- + Applies to
Integrations
Cookie Munch's ad/analytics integrations live in @cookiemunch/integrations (packages/integrations/src/index.ts) — a framework-agnostic, dependency-free layer of pure functions and "sinks" that translate a Cookie Munch consent decision into each platform's own consent signal. Site-embed integrations (GTM, WordPress, page builders) instead just install the same consent.js tag through a different channel. Nothing here imports a real ad SDK; every platform global (gtag, uetq, fbq, ttq, googletag, pbjs, …) is passed in as a parameter, so every adapter is pure and unit-testable without the vendor's script loaded.
Google Consent Mode v2
consentModeV2(state) is the single source of truth for the 7 Consent Mode v2 signals — the same mapping backs the web gtag sink, native Firebase mappers, and any custom code, so no platform's signals can drift from another's:
import { consentModeV2 } from '@cookiemunch/integrations';
consentModeV2({ preferences: true, statistics: true, marketing: false });
// → { ad_storage: 'denied', analytics_storage: 'granted', ad_user_data: 'denied',
// ad_personalization: 'denied', functionality_storage: 'granted',
// personalization_storage: 'granted', security_storage: 'granted' }The mapping: marketing → ad_storage + ad_user_data; statistics → analytics_storage; preferences → functionality_storage + personalization_storage; security_storage is always granted (strictly necessary). ad_personalization follows IAB TCF purpose 4 when granular state.tcf selections are present, otherwise it follows the coarse marketing gate.
Web: createGoogleConsentSink
import { createGoogleConsentSink, attachSink } from '@cookiemunch/integrations';
const sink = createGoogleConsentSink({ waitForUpdate: 500 }); // pushes onto window.dataLayer by default, or pass { gtag }
attachSink(window.CookieMunch, sink);attachSink fires emitDefault() once (a consent('default', …) call with everything denied except security_storage, plus ads_data_redaction and url_passthrough), then pushes the current consent state, then subscribes to every future change via onConsentChange.
Native / Firebase: firebaseConsent
firebaseConsent(state) derives the Firebase Analytics setConsent map (ANALYTICS_STORAGE, AD_STORAGE, AD_USER_DATA, AD_PERSONALIZATION) from consentModeV2, so native values are always identical to the corresponding web ones:
// iOS (Swift)
import FirebaseAnalytics
Analytics.setConsent([
.analyticsStorage: map["ANALYTICS_STORAGE"] == "granted" ? .granted : .denied,
.adStorage: map["AD_STORAGE"] == "granted" ? .granted : .denied,
.adUserData: map["AD_USER_DATA"] == "granted" ? .granted : .denied,
.adPersonalization: map["AD_PERSONALIZATION"] == "granted" ? .granted : .denied,
])// Android (Kotlin)
firebaseAnalytics.setConsent(mapOf(
ConsentType.ANALYTICS_STORAGE to status(map["ANALYTICS_STORAGE"]!!),
ConsentType.AD_STORAGE to status(map["AD_STORAGE"]!!),
ConsentType.AD_USER_DATA to status(map["AD_USER_DATA"]!!),
ConsentType.AD_PERSONALIZATION to status(map["AD_PERSONALIZATION"]!!),
))Call it once on app start with the persisted decision, and again from your consent client's onChange callback whenever the user updates consent.
Microsoft UET
createMicrosoftUetSink() pushes a single ad_storage signal onto window.uetq — UET only exposes the one signal, gated on marketing:
import { createMicrosoftUetSink, attachSink } from '@cookiemunch/integrations';
attachSink(window.CookieMunch, createMicrosoftUetSink());
// on consent: uetq.push(['consent', 'update', { ad_storage: 'granted' | 'denied' }])Meta Pixel
createMetaSink() calls fbq('consent', 'grant' | 'revoke') based on the marketing purpose:
import { createMetaSink, attachSink } from '@cookiemunch/integrations';
attachSink(window.CookieMunch, createMetaSink());Pass { fbq: myFbq } to override the global lookup (e.g. in tests).
TikTok Pixel
createTiktokSink() calls ttq.grantConsent() / ttq.revokeConsent(), again gated on marketing:
import { createTiktokSink, attachSink } from '@cookiemunch/integrations';
attachSink(window.CookieMunch, createTiktokSink());Universal ad-network toolkit
For ad stacks with no first-class sink, a smaller set of primitives shares the same convention: personalized/behavioral ads require marketing granted; contextual ads may keep running regardless.
adPersonalizationAllowed(consent)— the single source of truth (marketing === true).onAdConsent(api, cb)— subscribe; fires immediately with{ personalized, consent }and again on every change.applyGoogleAdManager(googletag, personalized)— queues ontogoogletag.cmd, preferssetPrivacySettings({ nonPersonalizedAds }), falls back to legacysetRequestNonPersonalizedAds.applyAdSense(personalized)— setsadsbygoogle.requestNonPersonalizedAds(must run before AdSense units load; for EEA/UK use the Consent Mode sink instead — NPA alone isn't the compliant path there).refreshPrebidOnConsent(pbjs, cb?)— re-runs the Prebid auction on consent change for non-TCF setups (Prebid's ownconsentManagementmodule readswindow.__tcfapiautomatically when TCF is enabled, so no manual wiring is needed in that case).createGenericAdSink(onChange)— wrap any in-house/custom ad server as aConsentSink.
import { onAdConsent, applyGoogleAdManager } from '@cookiemunch/integrations';
onAdConsent(window.CookieMunch, ({ personalized }) => {
applyGoogleAdManager(window.googletag, personalized);
});Site-embed integrations
Every channel below installs the same canonical <script id="CookieMunch"> tag — pick the one matching your stack; you only need one.
<script id="CookieMunch"
src="https://<host>/consent.js"
data-cbid="<SITE_ID>"
data-blockingmode="auto"></script>Place it as early in <head> as possible so automatic prior-blocking intercepts trackers before they run. Get the exact tag pre-filled via GET /v1/sites/{cbid}/snippet or client.sites.snippet(cbid) — see Client reference or the get_install_snippet MCP tool.
WordPress
Location: plugins/wordpress/forgeconsent/.
Upload to
wp-content/plugins/(or zip and use Plugins → Add New → Upload Plugin), then activate.Configure under Settings → Cookie Munch: API host, site id (
cbid), blocking mode, culture, enable toggle.The plugin injects the embed at
wp_headpriority1— as early as possible, even ahead of aggressively-enqueued analytics scripts.Render the cookie table anywhere with the
[cookiemunch_cookie_declaration]shortcode.
Google Tag Manager
Location: integrations/gtm/. Two install paths:
Option 1 — Custom Template (recommended): GTM → Templates → New → overflow menu → Import → integrations/gtm/template.tpl. Then Tags → New → choose the Cookie Munch template, fill in API host/cbid/blocking mode/culture, set the trigger to Consent Initialization - All Pages (fall back to Initialization - All Pages), then Submit / Publish.
Option 2 — Custom HTML (fallback): paste the canonical embed into a Custom HTML tag with "Support document.write" unchecked, same trigger, Submit / Publish.
The Custom Template passes cbid/blockingmode/culture via the consent.js query string plus a window.CookieMunchConfig global (GTM's sandboxed injectScript can't set data-* attributes); the Custom HTML fallback uses the literal data-* attributes and is byte-for-byte identical to a direct install.
Page builders (Shopify, Wix, Webflow, generic HTML)
Location: integrations/snippets/. Same canonical embed, different paste-point per platform:
Platform | Where |
|---|---|
Shopify |
|
Wix | Settings → Custom Code, added to |
Webflow | Site Settings → Custom Code → Head Code (site-wide). |
Generic HTML | Any hand-built or templated site — same tag, same placement rule. |
Cookie declaration table
A second, optional embed for a Cookie Policy page, listing scanned cookies by category:
<script src="https://<host>/cookie-declaration.js" data-cbid="<SITE_ID>"></script>Verify the install
After installing on any channel, open the site in a fresh session, confirm a request to /consent.js fires and the banner appears, then run POST /v1/sites/{cbid}/verify (dns/meta/file challenge) — domain verification unlocks consent CSV export and signed receipts for that site.