Why most cookie-banner blockers don't actually work
Install a typical cookie-banner blocker, then watch the network tab while you visit a site. Here is what actually happens:
- The page loads. The consent management platform (CMP) script executes and builds the banner.
- The blocker's CSS sets
display: noneon the banner element. - The banner disappears from your screen.
- The CMP never receives a "reject" signal. Non-essential scripts keep loading exactly as before.
That fourth step is the part almost nobody talks about.
Hiding is a cosmetic operation
A cookie banner is not a decorative overlay you're allowed to delete. It's the UI of a consent platform — a script that is supposed to record a decision and hand that decision to the tag manager, which then decides whether to fire analytics, ads, session replay, and so on.
If you remove the banner with CSS, you have removed the UI and left the machinery untouched. The page has no idea what you wanted, so it defaults to its own default, which is usually "everything on until told otherwise."
The visible result is identical. The legal and technical result is the opposite of what the user intended.
What a real opt-out actually requires
Consent platforms are designed to accept a decision from a few specific entry points. To genuinely reject, a tool has to use one of them:
-
Trigger the platform's own reject control — the same element a human would click, selected per platform (
#onetrust-reject-all-handler,[data-testid="reject-all"],button[aria-label*="reject"], …). It has to be the actual control, not a look-alike button the tool injects. -
Call the platform's public API, e.g. OneTrust's
OneTrust.RejectAll(), or Cookiebot's consent submit methods. These write the consent record that the tag manager reads. - Post a proper TCF v2 string for IAB-compliant platforms, so downstream vendors see a "no consent for purposes 1–10" state.
There is a reason most blockers skip this: it's platform-specific, the DOM changes constantly, and each CMP has its own naming. A CSS rule works on every site forever. An API call breaks next Tuesday. So the ecosystem settled on the version that's easy to maintain instead of the one that works.
The signal almost nobody sends: GPC
Global Privacy Control is a legally recognised opt-out preference signal under the CCPA/CPRA and several US state privacy laws. It has two parts:
1. A request header, Sec-GPC: 1 — trivial to add from an MV3 extension via a declarative rule:
{
"id": 1,
"priority": 1,
"action": {
"type": "modifyHeaders",
"requestHeaders": [
{ "header": "Sec-GPC", "operation": "set", "value": "1" }
]
},
"condition": {
"urlFilter": "*",
"resourceTypes": ["main_frame", "sub_frame"]
}
}
2. The JS property navigator.globalPrivacyControl, which sites can read directly. Chrome doesn't ship it (yet), so an extension has to define it in a content script running before page scripts:
try {
Object.defineProperty(navigator, "globalPrivacyControl", {
get: () => true,
configurable: false
});
} catch (e) { /* already defined */ }
Because it's a legal signal in some jurisdictions, a site that receives it is supposed to stop selling or sharing your data even without a banner interaction. Yet a quick audit of the popular CSS-hiding blockers shows most of them never send it. Hiding a banner is easy to demo; sending a header that no screenshot can show isn't.
Why this category went stale
Here's the part that made me actually build something.
The extension with the largest install base in this category was acquired a few years ago and — as of this writing — has not shipped an update since mid-2024. The store reviews have shifted accordingly: a large share of the nearly 1,900 ratings are now one star, and the top-voted comments read like "stopped working on many sites" and "breaks scrolling". Meanwhile a community fork that just keeps the rules updated has picked up a couple hundred thousand users.
That tells you two things:
- Users in this category do switch tools — the switching cost people assume exists isn't really there.
- The category's problem is maintenance, not novelty. Consent platforms change their DOM; a blocker that isn't updated decays into "hides some banners, silently fails on others."
The three constraints I built around
Full disclosure: I'm the developer of a blocker in this space, CookieGuard. I'm not going to claim it's "better" — I have too few users to make that claim honestly. What I can describe is the shape of the problem I constrained myself to, because each constraint comes straight from what the reviews complain about:
- Press the real button. Identifies the CMP by name (27 of them), triggers its genuine reject action or calls its own API; unknown banners fall back to a phrase library (224 don't-sell phrases across 35 languages); verifies the banner is actually gone rather than assuming.
- Don't break the page. The rejection is scoped to the banner it dismissed. No page rewriting, and it never clicks "Accept" on your behalf — a consent tool that accepts on your behalf is worse than no tool.
- Nothing leaves the machine. No account, no analytics, no telemetry. The optional per-site memory stores a hostname and the action you took, and clears in one click.
It's a manifest V3 extension, rules ship as a versioned JSON file (because that's the part that has to stay current), and the only outbound requests it makes are an optional daily rules fetch and licence activation.
The question I'd actually like answered
Treat the tool as irrelevant to this post. The design question is:
Should a consent tool be judged by whether the opt-out legally registers, or is hiding the banner good enough?
If the answer is "hiding is fine," then the entire GPC layer and the CMP-specific API calls are wasted complexity, and the whole category can stay six lines of CSS. If the answer is "it should actually register," then most of the popular tools are shipping the cosmetic version of a legal feature — and that's worth saying out loud.
Either way: if you've hit banners that neither approach handles, the shape of the failure is more useful to me than a rating. Tell me what the site was and what happened.
Top comments (0)