Script blocking is how a consent banner stops tracking code from running until a visitor agrees to it. Mechanically it is simpler than it sounds. The platform takes a script tag the browser would otherwise execute, neutralizes it, records which consent category it belongs to, and puts it back the moment that category is granted.
Key Takeaways
- 01Blocking works by neutralizing a tag before the browser runs it, usually by setting type to text/plain, then restoring it once the visitor consents.
- 02Every platform uses its own category attribute. Cookiebot uses data-cookieconsent, OneTrust uses optanon-category classes, Termly uses data-categories, CookieScript and Pandectes use data-cookiecategory.
- 03Iframes and images have no type attribute, so they are blocked differently. Cookiebot swaps src for data-cookieblock-src.
- 04Manual markup only blocks the tags you remember to mark. Anything added later by a tag manager, a plugin or another script goes straight through.
- 05Across 229 sites we scanned, 78 to 83 percent sent a third-party request before the visitor chose anything.
The neutralizing step is nearly always the same trick: set the tag's type to something the browser does not recognize as JavaScript, usually text/plain, and the browser treats the whole thing as inert text. What differs between platforms is the attribute that carries the category, and that is the part people actually get stuck on.
This page covers both: the mechanism, and the exact attribute each major consent platform expects.
What blocking actually does to a tag
A browser decides whether to run a script by looking at its type attribute. Give it a value it does not understand and the browser skips execution entirely, leaving the tag sitting in the DOM as text. Consent platforms use that as an off switch, then flip it back on after consent by restoring the real type and re-inserting the tag.
<!-- Normal: the browser runs this immediately -->
<script src="https://cdn.example-tracker.com/pixel.js"></script>
<!-- Blocked: inert until the visitor consents -->
<script type="text/plain"
data-cookieconsent="marketing"
src="https://cdn.example-tracker.com/pixel.js"></script>The important part is timing. This only works if the tag is neutralized before the browser reaches it. If a platform gets there late, the script has already run, the request has already gone out, and no amount of blocking afterwards undoes it. That single detail is the difference between a banner that works and a banner that is decorative.
The blocking attribute for every major CMP
The mechanism is shared, but the vocabulary is not. If you are moving between platforms, or debugging a site someone else set up, this is the translation table.
| Platform | Neutralized with | Category attribute | Example values |
|---|---|---|---|
| Cookiebot | type="text/plain" | data-cookieconsent | preferences, statistics, marketing |
| OneTrust | type="text/plain" | class="optanon-category-C000X" | C0001 necessary, C0002 performance, C0003 functional, C0004 targeting, C0005 social |
| Termly | type="text/plain" | data-categories | essential, performance, analytics, advertising, social networking |
| CookieScript | type="text/plain" plus data-cookiescript="accepted" | data-cookiecategory | strict, functionality, performance, targeting |
| Pandectes | type="javascript/blocked" | data-cookiecategory | functionality, performance, targeting |
| CookieYes | type="text/plain" | data-cookieyes | cookieyes-functional, cookieyes-analytics, cookieyes-advertisement |
| ConsentStack | type="text/plain", applied automatically | data-cs-category, override only | functional, analytics, marketing |
A few of these have sharp edges worth knowing. Cookiebot accepts combined values like data-cookieconsent="statistics, marketing", but necessary and unclassified are not valid values and should never be used: a necessary script should simply be left unmarked. Pandectes is the odd one out on the type value, using javascript/blocked rather than text/plain. And OneTrust carries its category in a class name rather than a data attribute, which is easy to miss when you are scanning markup for something that looks like a category.
<!-- Cookiebot -->
<script type="text/plain" data-cookieconsent="statistics"
src="https://example.com/analytics.js"></script>
<!-- OneTrust (C0002 = performance) -->
<script type="text/plain" class="optanon-category-C0002"
src="https://example.com/analytics.js"></script>
<!-- Termly -->
<script type="text/plain" data-categories="analytics"
src="https://example.com/analytics.js"></script>data-cookieblock-src, and why embeds are different
The text/plain trick only works on script tags, because they are the only ones with a type attribute the browser checks. Iframes and images have no such switch. Set an iframe's type to anything you like and it will still load a YouTube embed, along with the cookies that come with it.
So platforms take the other route: remove the thing that tells the element what to load. Cookiebot's version is data-cookieblock-src. You move the URL out of src and into that attribute, which leaves the element with nowhere to point until consent arrives, at which point Cookiebot moves it back. The reason it is not simply called data-src is that lazy-loading libraries had already claimed that name, and the two would fight over the same attribute.
<!-- Loads immediately, cookies and all -->
<iframe src="https://www.youtube.com/embed/VIDEO_ID"></iframe>
<!-- Held until marketing consent is given -->
<iframe data-cookieblock-src="https://www.youtube.com/embed/VIDEO_ID"
data-cookieconsent="marketing"
frameborder="0" allowfullscreen></iframe>Auto-blocking versus marking things up by hand
Every platform in that table offers two modes. Auto-blocking watches the page and intercepts anything that matches a maintained list of known trackers, without you touching your markup. Manual markup blocks exactly what you label and nothing else. Most sites end up running both, because auto-blocking handles the recognizable third parties while manual markup covers in-house scripts no list would know about.
Both modes need an escape hatch for scripts that auto-blocking grabs by mistake, and this is where a lot of debugging time goes. Every platform names that escape hatch differently, so the next section decodes each one. If a script you need is silently not running, an over-eager auto-blocker is the first thing to check. Google Tag Manager surfaces the same situation as its own warning, which we unpack in what "a consent management platform may be blocking tags" actually means.
The skip attribute for every major CMP
A skip attribute is the reverse of a blocking attribute: it tells the consent platform's auto-blocker to leave one specific script alone. Cookiebot calls it data-cookieconsent="ignore", OneTrust calls it data-ot-ignore, and ConsentStack calls it data-cs-category="ignore". Some platforms have no markup version at all and handle exemptions from the dashboard instead.
| Platform | Skip symbol | What it actually does |
|---|---|---|
| Cookiebot | data-cookieconsent="ignore" | Exempts the script from automatic blocking only. A tag that was also neutralized manually with type="text/plain" stays blocked |
| OneTrust | data-ot-ignore | Added to the script tag with no value. Auto-Blocking passes over the tag entirely |
| Termly | None. Dashboard only | Exemptions are set through Domain Rules in the Termly dashboard, not with a markup attribute |
| CookieYes | None documented | Auto-blocking follows its tracker list. There is no documented skip attribute to put on a tag |
| ConsentStack | data-cs-category="ignore" | Skips blocking and reporting. Use data-cs-category="essential" when a script should run before consent but stay visible in your tracker inventory |
<!-- Cookiebot -->
<script data-cookieconsent="ignore"
src="https://example.com/critical.js"></script>
<!-- OneTrust -->
<script data-ot-ignore
src="https://example.com/critical.js"></script>
<!-- ConsentStack -->
<script data-cs-category="ignore"
src="https://example.com/critical.js"></script>When someone reports that the ignore attribute is not working, it is nearly always one of three things. First, scope: Cookiebot's ignore value only reaches automatic blocking, so a tag that was also neutralized manually with type="text/plain" stays blocked no matter what the attribute says. Second, the attribute has to be on the tag the browser actually sees. If a page builder, a plugin or a tag manager injects the script at runtime, the attribute you wrote in a template never lands on the rendered tag, and the blocker has nothing to read. Third, people debug their source files instead of the rendered DOM. Open the element inspector and look at the tag that is actually on the page; it is often not the one you wrote.
Anything you exempt runs for every visitor, before any consent choice, in every region you serve. That is correct for genuinely essential scripts like authentication, payments and fraud prevention, and wrong for anything that sets tracking cookies. Keep the skip list short, and audit it whenever you audit the rest of your consent setup.
Why hand-marking scripts keeps leaking
Manual markup works perfectly on the tags you mark. The problem is that it is a hand-maintained list of things that change without telling you. Someone adds a tag in Google Tag Manager. A plugin update ships a new pixel. A marketer pastes a snippet into a template. A third-party script loads a fourth-party script. None of those arrive with your attribute on them, and none of them will be blocked.
This is why a site can be genuinely well configured and still fail a check. The markup is correct. The coverage is not. And because the tags that slip through are usually the ones added most recently, the gap tends to grow quietly between audits. We measured how often this happens in our State of Cookie Compliance study.
In our scan of 229 sites, 78 to 83 percent sent a request to a third party before the visitor had chosen anything. Among sites where a banner was present and Reject was actually clickable, 43 percent kept a genuine third-party tracker firing after Reject. These are behavioral measurements of what the pages did, not legal verdicts about the sites.
The cookie jar tells the same story after the click. Across 949 sites with a working Reject button, 43% of ghostwritten tracking cookies survived Reject All, and nearly all of them were set before the visitor chose anything.
How ConsentStack handles it
We took the view that if coverage is the failure mode, then hand-marking should be the exception rather than the default. ConsentStack classifies scripts by their domain against a maintained tracker list, so a newly added Meta Pixel or Hotjar tag is recognized and held the first time it appears, whether or not anyone remembered to label it. Blocked tags get the same text/plain treatment, and are restored in their original order once the matching category is granted.
The manual attribute still exists as an override, data-cs-category, for in-house scripts no list would recognize, and data-cs-category="ignore" exempts a script entirely. One honest exception: for platforms that expose a real consent API of their own, such as Google Consent Mode, the script is allowed to load and consent is passed through that API instead, because that is the integration those vendors are built around. If you want to see which of these your own site currently gets right, the free compliance scanner checks it from both an EU and a US vantage point.
Frequently Asked Questions
Script blocking is a mechanism that prevents a website's tracking scripts from running, and from setting cookies or sending data, until the visitor has consented to the relevant category. It works by neutralizing the script tag before the browser executes it, usually by setting its type attribute to text/plain, then restoring it once consent is given.
It is Cookiebot's attribute for blocking iframes and images, which have no type attribute to switch off. You move the URL from src into data-cookieblock-src, leaving the element with nothing to load. Cookiebot restores it to src once the category named in data-cookieconsent is consented to. It exists under that name rather than data-src to avoid clashing with lazy-loading libraries.
The most common causes are that the attribute is on the wrong element, that the script is injected later by a tag manager so your markup never applies to it, or that the type attribute was also changed to text/plain, which blocks the script regardless of the ignore value. Check the rendered DOM rather than your source template, since the tag you wrote is often not the tag that ends up on the page.
Not if your platform's auto-blocking covers it. Auto-blocking matches scripts against a known-tracker list and needs no markup, which is what catches tags added later by other people. Manual markup is best kept for in-house or unusual scripts that no list would recognize. Relying on manual markup alone is the most common reason otherwise well-configured sites still leak.
It can, if the wrong things get blocked. Auto-blocking sometimes catches a script your site genuinely needs to function. That is what the exemption attributes are for: data-cookieconsent="ignore" in Cookiebot, data-ot-ignore in OneTrust. Essential scripts like authentication, payments and security should never be marked with a consent category in the first place.
Load your site in a private window, open the browser's network tab before accepting anything, and look at which third-party domains are contacted. Then click Reject and watch again. Anything firing in either state that is not strictly essential is a leak. An automated scan does the same thing more thoroughly, including from a second geographic vantage point.
See what your site actually blocks
Enter your domain and get a free report on what fires before consent and what keeps firing after Reject, checked from both the EU and the US. No signup.
Related Posts
A Consent Management Platform (CMP) May Be Blocking Tags: What It Means and How to Fix It
Seeing "A Consent Management Platform (CMP) may be blocking tags" in Google Tag Assistant? It usually means your CMP is working correctly. Here is when it is a real problem, and how to fix it.
Is Google Analytics GDPR Compliant? (2026)
Not by default. GA4 can be used lawfully in the EU, but only if you get consent before it fires, run Consent Mode v2, accept Google's data terms, and rely on the Data Privacy Framework. Here is the full checklist, and the one step most sites get wrong.
Meet the Free Compliance Scanner: See Where Your Site Leaks Consent
Enter your domain and in about a minute see whether your site respects visitor consent, checked from both the EU and the US. Free, no signup.