Wiring with a CMP
Trackbridge gates click-identifier cookies on ad_storage consent (when consentMode: 'v2') but does not show a banner — that’s your CMP’s job. The integration is two callbacks: when the user grants consent, call tracker.updateConsent(...) with 'granted'; when they decline, call it with 'denied'.
This guide gives the wiring for the four common cases: Cookiebot, OneTrust, Iubenda, and rolling your own. For the underlying behavior, see Consent Mode v2.
Cookiebot
Section titled “Cookiebot”Cookiebot exposes CookiebotOnAccept and CookiebotOnDecline events on window, plus a window.Cookiebot.consent object with per-category booleans:
import { tracker } from '@/lib/tracker.client';
window.addEventListener('CookiebotOnAccept', () => { tracker.updateConsent({ ad_storage: window.Cookiebot.consent.marketing ? 'granted' : 'denied', ad_user_data: window.Cookiebot.consent.marketing ? 'granted' : 'denied', ad_personalization: window.Cookiebot.consent.marketing ? 'granted' : 'denied', analytics_storage: window.Cookiebot.consent.statistics ? 'granted' : 'denied', });});
window.addEventListener('CookiebotOnDecline', () => { tracker.updateConsent({ ad_storage: 'denied', ad_user_data: 'denied', ad_personalization: 'denied', analytics_storage: 'denied', });});Cookiebot also fires CookiebotOnLoad when its prior-choice cookie restores consent on a return visit. Listen for it too if you want to replay the saved choice without the user re-clicking the banner.
OneTrust
Section titled “OneTrust”OneTrust uses window.OptanonWrapper, called once after the SDK loads and again on every consent change. Group IDs are configured per project; the OneTrust defaults are C0001 (Strictly Necessary), C0002 (Performance), C0003 (Functional), C0004 (Targeting):
import { tracker } from '@/lib/tracker.client';
window.OptanonWrapper = function () { const groups = window.OnetrustActiveGroups || ''; const has = (id: string) => groups.includes(`,${id},`);
tracker.updateConsent({ ad_storage: has('C0004') ? 'granted' : 'denied', // Targeting ad_user_data: has('C0004') ? 'granted' : 'denied', ad_personalization: has('C0004') ? 'granted' : 'denied', analytics_storage: has('C0002') ? 'granted' : 'denied', // Performance });};Replace C0002 / C0004 with your project’s actual group IDs. They’re in your OneTrust admin under Cookies → Categories.
Iubenda
Section titled “Iubenda”Iubenda’s Consent Solution exposes a callback hook in the configuration object. The purpose IDs depend on your Iubenda project but 4 (Marketing) and 5 (Measurement) are the standards:
import { tracker } from '@/lib/tracker.client';
window._iub = window._iub || [];window._iub.csConfiguration = window._iub.csConfiguration || {};window._iub.csConfiguration.callback = { ...window._iub.csConfiguration.callback, onConsentRead: function () { const purposes = window._iub.cs.consent.purposes; tracker.updateConsent({ ad_storage: purposes['4'] ? 'granted' : 'denied', ad_user_data: purposes['4'] ? 'granted' : 'denied', ad_personalization: purposes['4'] ? 'granted' : 'denied', analytics_storage: purposes['5'] ? 'granted' : 'denied', }); },};onConsentRead fires both on first interaction and on subsequent page loads when the saved choice is replayed — which is exactly the wiring you want.
Custom CMP
Section titled “Custom CMP”If you’re rolling your own banner:
import { tracker } from '@/lib/tracker.client';
function onAcceptAll() { tracker.updateConsent({ ad_storage: 'granted', ad_user_data: 'granted', ad_personalization: 'granted', analytics_storage: 'granted', }); saveConsentChoice('all');}
function onAcceptEssentialOnly() { tracker.updateConsent({ ad_storage: 'denied', ad_user_data: 'denied', ad_personalization: 'denied', analytics_storage: 'denied', }); saveConsentChoice('essential');}
function onAcceptCustom(choices: { marketing: boolean; analytics: boolean }) { tracker.updateConsent({ ad_storage: choices.marketing ? 'granted' : 'denied', ad_user_data: choices.marketing ? 'granted' : 'denied', ad_personalization: choices.marketing ? 'granted' : 'denied', analytics_storage: choices.analytics ? 'granted' : 'denied', }); saveConsentChoice('custom', choices);}On every page load, replay the saved choice as soon as the tracker is created — don’t wait for the user to interact again:
const saved = readConsentChoice();if (saved) { tracker.updateConsent({ ad_storage: saved.marketing ? 'granted' : 'denied', ad_user_data: saved.marketing ? 'granted' : 'denied', ad_personalization: saved.marketing ? 'granted' : 'denied', analytics_storage: saved.analytics ? 'granted' : 'denied', });}Without the replay, every page load starts fresh and any captured gclid lives in memory only until consent is re-granted.
Verifying the wiring
Section titled “Verifying the wiring”- Open the site in a fresh incognito window with DevTools → Application → Cookies open.
- Land on the site with
?gclid=test123in the URL. - Confirm no
_tb_gclidcookie is present (consent is unknown). - Click Accept on the banner.
- Confirm
_tb_gclidnow appears with valuetest123. - Reload the page (drop the URL param). Confirm the cookie persists.
- Repeat from step 1, but click Decline. Confirm no cookie is written, even with
?gclid=test123in the URL.
If the cookie doesn’t appear after Accept, the CMP callback isn’t reaching the tracker. Add a console.log('[cmp] updateConsent', granted) inside the callback to confirm it fires.
Don’t forget gtag’s own consent
Section titled “Don’t forget gtag’s own consent”Trackbridge has its own consent state, separate from gtag’s. If you want gtag to also respect the user’s choice (which you usually do, for GA4 cookie behavior), call gtag’s consent API from the same CMP callback:
window.gtag('consent', 'update', { ad_storage: choices.marketing ? 'granted' : 'denied', ad_user_data: choices.marketing ? 'granted' : 'denied', ad_personalization: choices.marketing ? 'granted' : 'denied', analytics_storage: choices.analytics ? 'granted' : 'denied',});Trackbridge’s updateConsent does not call gtag('consent', ...) for you. That’s deliberate: not every project loads gtag, and projects that do may already wire gtag-consent through a separate path (Google Tag Manager, for instance).
See also
Section titled “See also”- Consent Mode v2 — the conceptual background.
tracker.updateConsent()— the API.trackbridge-consentskill — guided wiring for your specific CMP.