Script blocking & data-attributes
- Written for
- + Written for
- Deprecated
- + Deprecated
- Applies to
- + Applies to
Script blocking & data-attributes
Cookie Munch's core promise is prior blocking: no non-necessary tracker script runs before the visitor has consented. @cookiemunch/core implements this two ways — automatic (packages/core/src/blocker/auto.ts) and manual (packages/core/src/blocker/manual.ts) — that share one reactivation mechanism and one attribute vocabulary, so you can mix them on the same page.
Automatic blocking (data-blockingmode="auto", the default)
With data-blockingmode="auto" on the install tag, the embed calls installAutoBlocker() synchronously, before any per-site config fetch, which:
Monkey-patches
Node.prototype.appendChildandNode.prototype.insertBefore— the two paths through which scripts and pixels get inserted, whether by inline HTML parsing, a tag manager'sinjectScript, or your own JS.Installs a
MutationObserverondocument.documentElementto also catch parser-inserted nodes the patched methods don't see directly.
Every inserted SCRIPT, IFRAME, IMG, LINK, EMBED, OBJECT, AUDIO, VIDEO, and SOURCE element — and every matching descendant of an inserted subtree — is checked the instant it's inserted, before the browser fetches or executes it. Each one is classified against a checklist of known tracker domains (Google Analytics, Google/Meta/TikTok/LinkedIn ad pixels, Hotjar, Clarity, Mixpanel, Segment, Matomo, YouTube/Vimeo embeds, and more — see packages/core/src/blocker/checklist.ts), plus any site-specific rules from a completed cookie scan. If the match resolves to a category that isn't yet granted, the element is neutralized in place:
<script>elements gettype="text/plain"— inert; the browser parses but does not execute them.Everything else gets its
srcmoved todata-cookieblock-srcand the realsrcattribute removed, so the browser never fetches it.Either way,
data-cookieconsent="<category>"is written onto the element, recording why it was blocked — the same attribute manual markup uses, so one reactivation path (reactivate()inblocker/manual.ts) handles both.
You write no markup at all for this to work — GTM containers, third-party snippets pasted verbatim, whatever's already on the page gets caught. Notably, the bundled checklist deliberately does not block the GTM container script itself (googletagmanager.com/gtm.js) — blocking GTM wholesale would break Google Consent Mode, which relies on GTM loading and self-throttling its own tags; gtag.js is classified as statistics.
Two escape hatches exist for elements the auto-blocker would otherwise catch:
Mechanism | Effect |
|---|---|
| Never auto-blocked, even if it matches a checklist pattern. Useful for a first-party script whose URL happens to contain a matched string. |
| CSS selectors the auto-blocker never even inspects — a config-level allowlist (set via the dashboard or |
Elements already neutralized (a <script type="text/plain"> or one already carrying data-cookieblock-src) are skipped, so the blocker is idempotent against elements you mark up by hand.
Manual markup (data-blockingmode="manual")
In manual mode the auto-blocker is never installed; you mark each tracking tag inert yourself, using exactly the attribute vocabulary the auto-blocker writes:
<!-- Single category -->
<script type="text/plain" data-cookieconsent="statistics"
src="https://www.google-analytics.com/analytics.js"></script>
<!-- Requires BOTH categories granted before it runs -->
<script type="text/plain" data-cookieconsent="statistics,marketing"
src="https://example.com/combined-pixel.js"></script>
<!-- Non-script resource: real src goes in data-cookieblock-src -->
<iframe data-cookieblock-src="https://www.youtube.com/embed/xyz"
data-cookieconsent="marketing"></iframe>Attribute | Applies to | Values | Description |
|---|---|---|---|
|
| — | Marks the tag inert. On activation, Cookie Munch doesn't just flip the attribute — it re-creates the node (a fresh |
| any blockable element |
| The categories required before the element activates — all listed categories must be granted (an AND, not an OR). |
| non-script resources ( | a URL | Holds the real |
| any blockable element | any category id — standard or custom (comma-separated) | Cookie Munch's own alternative to |
data-cookieconsent only ever validates the three user-toggleable standard categories (preferences, statistics, marketing) plus the literal ignore — necessary and any custom category id are rejected by isValidMarkupCategory()/ parseMarkupCategories() when read from markup you write. If a site defines custom categories (Banner Studio v2), tag those scripts data-fc-category="my-custom-id" instead — the reactivation logic checks data-fc-category first and falls through to data-cookieconsent only when it's absent, so the two never conflict on one element.
Reactivation runs on every consent change (accept, decline, granular save, or withdrawal re-blocking) and re-scans the document each time, so elements added to the DOM after the fact are picked up on the next consent change, not retroactively — mark up static HTML for this path; use auto-blocking (or your own onConsentChange gating) for dynamically-injected content.
Placeholder elements
For consent-gated embeds where you want to show something instead of silently loading nothing (e.g. "Enable this video to watch"), two class-based hooks need no JS:
<div class="cookieconsent-optin-marketing">
<!-- shown once marketing is granted -->
</div>
<div class="cookieconsent-optout-marketing">
Please accept marketing cookies to view this content.
<!-- shown until marketing is granted -->
</div>On every reactivation pass, Cookie Munch toggles the hidden attribute on every element matching .cookieconsent-optin-<category> / .cookieconsent-optout-<category> for each of the three toggleable categories (preferences, statistics, marketing) — visible when granted for optin, visible when not granted for optout.
Per-category blocking in practice
Because data-cookieconsent/data-fc-category accept a comma-separated list, you can require more than one category for a single tag — e.g. a combined analytics+ads pixel that should only fire once both statistics and marketing are granted:
<script type="text/plain" data-cookieconsent="statistics,marketing"
src="https://example.com/combined-pixel.js"></script>and, for a Banner Studio custom category alongside a standard one:
<script type="text/plain" data-fc-category="statistics,partner-sync"
src="https://partner.example.com/sync.js"></script>isCategoryGranted() resolves each id — standard categories against the four core flags, custom ids by looking up their mapsTo in the site's v2 category config — and reactivate() requires every listed id to individually resolve to granted.
Migrating from Cookiebot
Every attribute above — data-cookieconsent, type="text/plain", data-cookieblock-src — is Cookiebot's own attribute vocabulary, verbatim. Combined with the install tag accepting id="Cookiebot" and window.Cookiebot aliasing window.CookieMunch, an existing Cookiebot site with manually-marked-up tags works unmodified after only swapping the <script src> — no HTML changes needed unless you're introducing a custom category, which is the one Cookie Munch-native addition (data-fc-category). The consent cookie reader also tolerates Cookiebot's own relaxed JS-object-literal value format ({stamp:'...',necessary:true,...}, single-quoted, unquoted keys) as a fallback when the value isn't valid JSON (parseCookiebotLegacy() in packages/core/src/cookie.ts), so a value written in Cookiebot's format under the shared cookie name is still understood after migration.
Next: JavaScript API to react to consent changes from your own code, or back to embed scripts for the install tag and its attributes.