Embed scripts (consent.js)
- Written for
- + Written for
- Deprecated
- + Deprecated
- Applies to
- + Applies to
Embed scripts (consent.js)
Cookie Munch protects a site with a single <script> tag. It loads consent.js — a small, dependency-free IIFE built from @cookiemunch/core — which installs prior-blocking, fetches the site's live dashboard config, detects the visitor's region, and renders the banner. Everything else (the JS API, script-blocking markup) builds on top of this one tag.
The install tag
<script id="CookieMunch"
src="https://cdn.cookiemunch.net/consent.js"
data-api="https://api.cookiemunch.net"
data-cbid="your-site-id"
data-blockingmode="auto"></script>Place it as early as possible in <head>, before any analytics or marketing tags. consent.js installs its DOM-interception blocker synchronously, on the very first line it executes — but it can only intercept scripts that are inserted after it runs, so placement above everything else is what makes prior-blocking actually prior.
The embed looks up its own <script> element by id, checking #CookieMunch first, then #Cookiebot, then falling back to document.currentScript. Accepting the Cookiebot id is deliberate: an existing Cookiebot install can switch to Cookie Munch by only swapping the src, with no HTML restructuring.
Attributes
Attribute | Required | Values | Description |
|---|---|---|---|
| yes | URL | The |
| yes | string | The site id issued when the site was registered. Read via |
| no |
| Only the literal string |
| no | URL (origin) | Overrides the origin used for the config fetch ( |
| no | a culture code, e.g. | Seeds the initial banner language, overriding auto-detection from |
There is no data-geolocation or region-forcing attribute on the tag itself — region comes from the server's own visitor-geolocation at config-fetch time and from navigator.globalPrivacyControl client-side, not from a script attribute.
Three ways to set the same three settings
cbid, blockingmode, and culture can each come from three places, resolved with this precedence (highest wins):
data-*attributes on the tag —data-cbid,data-blockingmode,data-culture.window.CookieMunchConfig— a plain object set beforeconsent.jsruns:<script>window.CookieMunchConfig = { cbid: 'your-site-id', blockingmode: 'auto' };</script> <script src="https://cdn.cookiemunch.net/consent.js"></script>This exists because some loaders — notably Google Tag Manager's sandboxed
injectScript— cannot setdata-*attributes on the tag they inject, but can run arbitrary JS beforehand to set a global.The
srcquery string —...consent.js?cbid=your-site-id&blockingmode=auto. Parsed withnew URL(src, location.href), so both absolute and relativesrcvalues work.
Each field is resolved independently, so you can mix sources (e.g. data-cbid on the tag plus blockingmode from the global) — resolveScriptConfig picks per-field, not per-source.
What happens on load
The production entry point (startWithRemoteConfig, what consent.js actually runs) does, in order:
Reads the script tag / global / query as above and resolves
cbid,blockingmode,culture. Nocbid→ the embed is a no-op.Installs the auto-blocker synchronously, if
data-blockingmode="auto"and the visitor isn't a recognized crawler — before fetching anything, so there is no window where a script can slip through while the network round-trip to fetch config is in flight.Fetches
GET <api-origin>/config/:cbidto hydrate the real dashboard config (banner content/theme, geo rules, blockingignoreSelectors, IAB framework settings, visitor region). On any failure — offline, CORS, an outage — it silently keeps the attribute-only base config instead of leaving the page unprotected or throwing.Builds the CMP from the hydrated config. The very first thing this step does is emit Google Consent Mode's default-denied signal (if enabled), ahead of installing the TCF/GPP/USP stubs, ahead of the banner, and ahead of any vendor tag.
Resolves the banner mode (opt-in / opt-out / off) from geo rules and the visitor's region, honoring Global Privacy Control as a forced decline where it applies.
Renders the banner (or applies implied consent silently, depending on mode) and exposes
window.CookieMunch(and thewindow.Cookiebotalias) — see the JavaScript API.Beacons anonymous impression (
dialogDisplay) and consent-decision events back to the API origin, unauthenticated by design since the embed runs in an untrusted browser context.
Note that steps 4-7 all happen after the config fetch resolves (or fails) — only the auto-blocker in step 2 runs synchronously ahead of the network round-trip. This is sufficient because prior-blocking's job is to stop vendor scripts from running before consent, and those are what step 2 already intercepts; Consent Mode's default signal only needs to precede the vendor tags it configures (e.g. gtag.js/GTM), which the auto-blocker is itself holding back until then.
Two bundles: consent.js vs. consent-tcf.js
@cookiemunch/core's tsup.config.ts emits three build targets from one package: an ESM index.js (consumed by @cookiemunch/react and the server, not shipped to browsers directly), and two browser IIFEs:
consent.js— the base embed, built fromsrc/embed.ts, minified, targetinges2020, with a hard 32KB gzip budget enforced in CI. It contains the prior-blocking engine, the banner UI, Google Consent Mode wiring, and lightweight synchronous stubs for__tcfapi/__gpp/__uspapiplus a lazy-loader — but none of the actual IAB TC-string/GVL logic.consent-tcf.js— built fromsrc/embed-tcf.tswithnoExternal: [/.*/](every dependency inlined, no externals), so it is fully self-contained. It carries the heavy@cookiemunch/tcf-derived TCF/GPP/USP encoding logic.
consent.js loads consent-tcf.js lazily, and only when a site has an IAB framework (framework: "iab"), GPP, or US-Privacy enabled in its config — most sites never pay for it. You never reference consent-tcf.js in your own HTML; it's fetched automatically from the same origin as data-api when needed. If you're building or touching @cookiemunch/core, note the dependency direction is one-way and enforced by convention: consent-tcf.js must never be imported from the base embed's module graph, or the 32KB gate breaks.
CDN and self-hosting
In the hosted product, consent.js and consent-tcf.js are served from https://cdn.cookiemunch.net, a separate static origin from the API (https://api.cookiemunch.net) — which is exactly the case data-api exists for. If you self-host the whole stack (docker compose up --build, or packages/server directly), the API server itself serves the built embed, so a bare src pointing at your server is enough and data-api can usually be omitted; the embed derives the API origin from src's own origin when data-api isn't set.
Async, defer, and placement
Do not add async or defer to the install tag. Prior-blocking only protects scripts inserted after consent.js has started executing and patched Node.prototype.appendChild/insertBefore; deferring or asyncing the tag lets the browser parse and potentially start executing later inline/synchronous scripts first, reopening exactly the race the tag exists to close. A plain, synchronous, head-first <script> — as in the install snippet above — is the supported configuration.
Next: JavaScript API for window.CookieMunch, or script blocking & data-attributes for how prior-blocking actually rewrites your tags.