┌── POST 08.28 · Cookie Audits & Scanners · 6 min read

Refusing Doesn’t Delete: The Cookie Failure Your CMP Can’t Fix

Reject all stops new trackers loading; it rarely removes what is already on the device. The CNIL sanctions that specifically. Why browsers make most of the deletion impossible from your page, what you can actually clear, and how to test the withdrawal path.

TL;DR

“Reject all” usually stops new trackers from loading. It very often does not remove the ones already on the device — and the CNIL sanctions that specifically: failing to give effect to a refusal or a withdrawal of consent was one of three grounds behind 21 tracker sanctions in 2025. The reason is technical rather than negligent: a consent manager controls what loads, and a page simply cannot delete most of what is already there. Here is what is actually deletable, what is not, and how to check.

There is a failure mode that survives every audit built around the question “does the banner block scripts before consent”. It passes that test cleanly and still leaves you exposed, because it happens after the click, on the refusal path that almost nobody exercises in testing.

The user clicks Reject. The banner disappears. And the cookies that were already on the device stay there, and keep being sent on every subsequent request.

The regulator’s view

The CNIL lists three grounds behind the 21 organisations it sanctioned over cookies and trackers in 2025. The third is failing to give effect to the user’s refusal or their withdrawal of consent — listed alongside placing trackers without consent at all, and inadequate information.

It is worth sitting with that. Not respecting a refusal is treated as its own violation, at the same level as never asking. Which follows logically: a refusal that changes nothing observable is indistinguishable from no mechanism at all.

The scale of the neighbouring penalties tells you it is not a technicality. In September 2025 the CNIL fined Google 325 million euros — for ads placed between Gmail messages without consent, and for setting trackers during account creation without valid consent, affecting more than 74 million accounts counting French residents alone — and SHEIN 150 million euros over the rules on trackers, as part of a cookie action plan it has run since 2019.

Why your CMP cannot fix this on its own

A consent manager’s core competence is deciding whether a script executes. That is a gate on the future. Deleting a cookie already written is a different operation, and the browser puts hard limits on who may perform it.

Cookies you cannot delete from your page, no matter the CMP

  • Cookies on another registrable domain. If a third party set a cookie on its own domain, your JavaScript cannot touch it. Same-origin policy is not a setting you can configure around. Only that third party can clear it, from its own context.
  • httpOnly cookies. They are invisible to document.cookie by design — that is the entire point of the flag. Your cleanup loop cannot see them, so it cannot expire them, and it will report success while they remain.

Cookies you can delete, but usually get wrong

  • Path and domain must match exactly. Expiring a cookie requires re-setting it with the same name, domain and path. Code that clears cookies at path=/ silently misses anything written at /app. The cookie stays, and nothing errors.
  • Host-only versus domain cookies. A cookie set on .example.com and one set on example.com are different entries. Clearing one leaves the other.

The storage that is not cookies at all

This is where most cleanup code stops looking. localStorage, sessionStorage and IndexedDB are not cookies, are not touched by any cookie-clearing routine, and are used routinely by analytics and session-replay tools to persist identifiers. A site can honour a refusal perfectly at the cookie level and keep a stable user ID in localStorage indefinitely.

Under ePrivacy the relevant act is storing or accessing information on the user’s device. The rule has never been about the word “cookie” — which is why an implementation that only reasons about cookies is reasoning about the wrong set.

The withdrawal case, which is worse

Everything above concerns a first-visit refusal, where relatively little has been set. Withdrawal is the harder one, and it is explicitly named in the CNIL’s ground.

A user accepts everything. They browse for a month. Analytics, advertising and session tools accumulate identifiers across cookies and local storage. Then they change their mind and switch everything off.

At that moment your CMP stops loading those scripts, and that is genuinely all it does. Every identifier written over that month is still on the device, still readable if anything ever loads again, and still attached to outbound requests to any domain that set a cookie. The user believes they have withdrawn. Technically they have revoked future collection and nothing else.

Test this path deliberately, because it is the one your users will actually take and the one nobody QAs.

What to actually do

  1. Clear on refusal, explicitly. Do not assume your CMP does it. Most gate loading and stop there. Wire your own cleanup to the refusal and withdrawal callbacks — both events, not just the first.
  2. Enumerate, do not guess. Iterate over the cookies that are actually present rather than a hardcoded list that went stale two deploys ago, and clear each across the domain and path variants that could apply.
  3. Include the other storage. Clear the localStorage, sessionStorage and IndexedDB keys owned by the tools you gate. This needs a real inventory of which tool writes what.
  4. For third-party cookies you cannot reach, stop the loading and document it. You genuinely cannot delete them from your page. What you can do is ensure nothing re-sets them, and be able to explain the limitation — which is a far better position than assuming they vanished.
  5. Re-test after every change to the tag stack. This regresses silently, like everything else in consent.

How to check yours in three minutes

Open a clean browser profile. Load your site and accept everything. Browse a few pages so the tools have a reason to write. Now open preferences and reject everything.

Then look in DevTools under Application: Cookies, Local Storage, Session Storage, IndexedDB. Anything still holding an identifier is something your refusal did not reach.

Do the same on the first-visit refusal path, which should be cleaner but frequently is not, because something wrote before the banner resolved — the failure we covered in the pre-consent tracking checklist.

Doing this by hand once tells you where you stand today. It does not tell you where you stand after the next deploy, which is the part that matters, because this is a regression rather than a bug — it comes back when someone adds a tool that nobody wires into the cleanup. Run it continuously so the gap between what your banner promises and what the device holds does not reopen unnoticed.

The short version

Blocking before consent is the well-known half of the problem and the one everybody tests. Honouring a refusal afterwards is the half that gets sanctioned in the same breath and almost never gets tested, because it requires clicking Reject and then looking — and most of the deletion the user assumes is happening is not technically possible from your page at all.

Know which parts you can clear, clear those properly, and be honest about the rest. That combination is defensible. Assuming the banner handled it is not.

C
About the author
Consent Mode HQ
Editorial team at Consent Mode HQ
Read more by author ↗