Your "Reject all" button doesn't actually reject
If Reject leaves tracking cookies in place — or adds new ones — the consent flow is misleading, and the legal exposure is the same as having no reject button at all. This often happens when third-party scripts ignore the CMP signal or when tag managers fire before the consent state propagates.
- If Reject still leaves trackers running, your consent flow is broken — not "mostly OK".
- Usually caused by scripts that ignore the CMP, or race conditions firing before the Reject signal propagates.
- Audit every script in your tag manager and every
<script>in your theme for consent awareness.
What the law says
If the Reject button doesn't actually reject, there is no valid consent and there is a deceptive design pattern — the user was given a choice that didn't reflect what actually happens. The DPC and EDPB both treat this as worse than having no Reject button at all, because it creates a false record of users "choosing" to allow tracking.
The EDPB Guidelines 03/2022 on deceptive design list "false hierarchy" and "misleading action" patterns where the UI suggests one outcome and the underlying system does another. A Reject button that doesn't stop tracking is the textbook example.
Why it matters
Beyond the ePrivacy and GDPR exposure, a broken Reject flow is the fastest way to attract a NOYB complaint or a DPC sweep follow-up. Regulators specifically test for this by clicking Reject and then inspecting cookies + network — exactly what our checker does. A report that fails this check makes it trivial for a complainant to attach evidence.
How to fix it
1. Reproduce the issue manually
Open an incognito window, visit the site, click Reject, then:
- Open DevTools > Application > Cookies. Note every cookie.
- Reload the page (still in the same session).
- Check cookies again — any new non-essential cookies are your problem.
- In Network, filter by your tracker domains (e.g. "google-analytics", "facebook"). Any requests are also the problem.
2. Check for CMP bypass
The most common cause is a script that loads without going through the CMP. Examples:
- Hard-coded
<script>in the site template, added before the CMP was installed. - A Shopify app that injects its own pixels directly into the theme.
- A WordPress plugin (Elementor Pro, HubSpot, Jetpack) that ships with tracking baked in.
- A "custom HTML" tag in GTM that's fired unconditionally rather than being gated on the consent trigger.
In OneTrust/Cookiebot/Didomi, any script that wasn't categorised by
the CMP continues to run normally. Find these by searching your site
HTML for tracker URLs (google-analytics.com,
googletagmanager.com, connect.facebook.net,
hotjar.com, etc.) and then checking that each tag has a
type="text/plain" (or equivalent CMP-specific attribute)
that blocks it until consent.
3. Check GTM Consent Mode is wired to Reject
If you use Google Tag Manager, your Reject handler must push a
consent update that denies every relevant signal — not just
analytics_storage:
// In your CMP's reject callback:
gtag('consent', 'update', {
ad_storage: 'denied',
ad_user_data: 'denied',
ad_personalization: 'denied',
analytics_storage: 'denied',
functionality_storage: 'denied',
personalization_storage: 'denied',
}); Then check your GTM tags: each one should have a "Consent Settings" configuration listing the signals it requires. A tag with no consent settings will fire regardless.
4. Fix race conditions
Some sites show the banner, the user clicks Reject, but scripts have already been queued and fire milliseconds later. Two causes:
- Banner loads async. If the CMP loads after tracker scripts, the trackers already ran. Move the CMP to the top of
<head>and load it synchronously; it's one of the rare cases where render-blocking is the right call. wait_for_updatetoo short. If you use GTM Consent Modedefaultwithwait_for_update: 500, a slow CMP decision can miss that window. Increase to 2000ms or have the CMP callgtag('consent', 'default', ...)itself instead of letting GTM guess.
5. Remove scripts that don't respect consent
Some third-party tools simply can't be gated — they hard-code their own cookie-setting behaviour and ignore consent signals. If a vendor can't honour Reject, either (a) don't use them, or (b) move them behind an explicit opt-in inside your preference centre so they only load for users who actively opt in. The vendor library notes which vendors support consent integration properly.
6. Clear leftover cookies on Reject
If a cookie was set before Reject (say, by a previous visit where the user accepted and has now changed their mind), deleting it on Reject is good practice. The CMP should do this for you; if it doesn't, loop over known tracker cookies and clear them:
const toClear = ['_ga', '_gid', '_gat', '_fbp', '_hjSessionUser_XXX'];
for (const name of toClear) {
// Overwrite with past-dated expiry across likely domain/path variants.
const domains = ['', '.' + location.hostname, location.hostname];
for (const d of domains) {
document.cookie =
name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/' +
(d ? '; domain=' + d : '');
}
} How to verify the fix
Re-run the cookie banner checker. The "Clicking Reject all does not add non-essential cookies" check simulates a real user: banner detected, Reject clicked, then cookie state compared before and after. A pass here, combined with the other two consent-related checks, is what the DPC will look for in a sweep.
Related fixes
- Your site has no cookie banner
- Your banner has no "Reject all" button
- Non-essential cookies are being set before consent
cookies.ie is not a law firm. A broken consent flow is usually fixable with configuration alone; if you suspect a deeper issue with a specific vendor, consult a data-protection lawyer.