Cookie consent in 2026: what changed and what site owners need to do
Google Consent Mode v2, IAB TCF v2.2, and the EU's Digital Markets Act all hit production in the last 18 months. Here's what site operators actually need to ship to stay compliant — and keep AdSense revenue.

This article is currently only available in English. A ภาษาไทย translation is coming soon.

If you operate a website that shows ads, runs analytics, or serves users in the EEA, the ground shifted in 2024–2025 and a lot of small operators never got the memo. This post is the practical TL;DR: what changed, why it matters, and what to actually deploy.
We just shipped this stack on stax.tools, so the examples are concrete, not theoretical.
What changed (the short version)
Three rules took effect at roughly the same time:
Google Consent Mode v2 (mandatory March 2024). Google now requires advertisers and publishers using AdSense, Google Ads, or Google Analytics to send four explicit consent signals —
ad_storage,ad_user_data,ad_personalization,analytics_storage— before personalised ads or full analytics fire for users in EEA, the UK, or Switzerland.IAB TCF v2.2 (mandatory May 2024). The IAB's Transparency and Consent Framework moved to v2.2, which removed "legitimate interest" as a basis for advertising for most purposes and tightened the "withdraw consent" UX requirement. If you're using a CMP (Consent Management Platform) that broadcasts a TCF string, it must be v2.2-certified.
Google's certified-CMP requirement (mandatory January 16, 2024). Sites running Google Ads/AdSense for EEA traffic must integrate a Google-certified CMP — either Google's own (free, built into AdSense as Funding Choices), or one of the certified third parties (Cookiebot, OneTrust, CookieYes, Iubenda, etc.).
Miss any of these and the consequences range from "AdSense quietly serves only non-personalised ads" (revenue cut by 40–60%) to "AdSense application gets rejected" to "GDPR enforcement action with a fine up to 4% of global revenue."
What you actually need to ship
Six pieces, in priority order:
1. A CMP that fires before any tracking script
Whether you use Google's free CMP or a third-party one, the banner must appear on first visit, before GA, AdSense, Pixel, or anything else gets a chance to set cookies. The classic mistake is loading GA in <head> and the banner in <body> — by the time the user clicks Decline, GA has already set _ga cookies.
The fix is the next item.
2. Consent Mode v2 defaults set BEFORE GA loads
This is the technical kernel of compliance. Before any analytics or ad library loads, you push consent defaults to dataLayer:
<script>
window.dataLayer = window.dataLayer || [];
function gtag() { dataLayer.push(arguments); }
gtag('consent', 'default', {
'ad_storage': 'denied',
'ad_user_data': 'denied',
'ad_personalization': 'denied',
'analytics_storage': 'denied',
'functionality_storage': 'granted',
'personalization_storage': 'granted',
'security_storage': 'granted',
'wait_for_update': 500
});
</script>
wait_for_update: 500 tells GA to hold sending data for 500ms so the user's Accept click can upgrade signals before the first measurement ping. This is the critical detail most tutorials miss.
When the user accepts, your CMP (or your custom code) calls:
gtag('consent', 'update', {
'ad_storage': 'granted',
'ad_user_data': 'granted',
'ad_personalization': 'granted',
'analytics_storage': 'granted'
});
GA, AdSense, and DV360 all listen for these signals and adjust behaviour. With denied, GA sends a privacy-safe "cookieless ping" (URL, country, time) that lets it model the missing data without setting any cookies — you don't lose all your data, you lose the personally-identifying parts.
3. A Reject-all button at the same level as Accept
The CNIL (France's data authority) fined Google €150 million in 2022 specifically because rejecting cookies took more clicks than accepting them. This pattern — Accept big and visible, Reject buried under "Manage options" — is now treated as a dark pattern under GDPR.
If you're using Google's CMP, choose the 3-button variant (Consent / Do not consent / Manage options), not the 2-button. Most third-party CMPs default to the 3-button layout already.
4. A privacy policy that actually names what you do
AdSense reviewers literally check that your privacy page mentions:
- "Google AdSense" by name
- Third-party vendor cookies for personalised advertising
- A link to Google Ad Settings for opt-out
- A link to aboutads.info (US) or youronlinechoices.com (EU)
- A description of Consent Mode behaviour at each consent state
A vague "we use cookies for analytics" isn't enough anymore.
5. A cookie table (helpful but not strictly required)
GDPR's transparency principle means listing the cookies you set, what they do, and how long they live. Plugins like AIOSEO and Cookiebot generate this automatically. If you write your own privacy page, a small HTML table covering _ga, _clck, __gads, your consent storage cookie, and your locale cookie is enough.
6. A way to withdraw consent
Once consent is given, users have the right to revoke it. Practically, this means either:
- Re-showing the CMP banner if the user clicks a "Manage cookies" link, OR
- Letting them clear browser storage for your site (which makes consent default back to
deniednext visit).
Option 2 is what most CMP-free sites do; if you've adopted Google's CMP, it provides the manage-link UX automatically.
What this looks like in production
On stax.tools, the wiring is:
- Consent default script in the HTML head with
strategy="beforeInteractive"so Consent Mode v2 signals are denied before any GA library loads. - Cookie banner component updates the gtag signals to
grantedon Accept, and writes the choice tolocalStorageso returning visitors don't see the banner again. - ClarityInit component reads the same
localStorageflag and callsclarity.consent(boolean)so Microsoft Clarity also respects the choice. - Google's CMP layered on top for EEA visitors, providing the certified TCF v2.2 integration AdSense requires.
- Privacy page with the full disclosure block (AdSense by name, opt-out links, cookie table, Consent Mode description).
Total code added: roughly 80 lines of JavaScript and a 200-line privacy page. Total third-party SaaS bills: $0 (Google's CMP is free).
Compliance is a moving target
The rules will change again. The EU's Digital Markets Act tightened in 2025; the UK is finalising post-Brexit cookie rules; California passed CPRA enforcement that broadens "sensitive personal information." The good news: Consent Mode v2 + a certified CMP gets you ~90% of the way to whatever the next iteration looks like, because all of these regimes converge on the same primitives: explicit signals, named purposes, easy revocation, no dark patterns.
Ship the six items above and you're in good shape for both the regulator's auditor and Google's reviewer.
Common implementation mistakes — and how to avoid them
After reviewing dozens of CMP implementations across small sites, these are the most frequent mistakes:
Mistake 1: Loading GA before the consent script
The single most common error. If your HTML loads gtag.js in <head> and your banner appears in <body>, GA fires before the user can decline. The fix is always to set the consent default before the GA library script tag — not before the gtag('config') call, but before the library loads at all.
Mistake 2: Using wait_for_update: 0 or omitting it
Without wait_for_update, GA sends a cookieless ping immediately on page load with the default (denied) state — even if the user Accepts within 0.5 seconds. Setting wait_for_update: 500 creates a window where an immediate Accept upgrades the signals before the first ping fires. This is the difference between losing vs. preserving analytics data for quick-accept users.
Mistake 3: Not persisting the consent choice
If you don't save the Accept/Decline to localStorage or a cookie, returning visitors see the banner on every page load. This is annoying and — more importantly — it means you're re-calling gtag('consent', 'update', {granted}) on every page visit, which looks unusual in the consent signal flow. Store the choice after the user clicks.
Mistake 4: Using localStorage for the consent signal in Next.js or SSR apps
localStorage is unavailable on the server. In SSR frameworks, the consent default script must either use a cookie (accessible server-side) or run exclusively client-side with "use client". The consent default <script> should run with strategy="beforeInteractive" (Next.js Script component) to ensure it runs before React hydration. Reading localStorage inside this script is safe because it runs only in the browser, not during server-side rendering.
Mistake 5: Having a separate Reject button that's smaller or less visible than Accept
This is the "dark pattern" that regulators target specifically. Both Accept and Decline must be visually equivalent — same button size, same prominence, same number of clicks to reach. If you use a "Manage preferences" option, the Reject option within that must also be reachable in one click — not buried in a nested settings panel.
Testing your implementation
After shipping, verify the implementation with these four checks:
Check 1: New visitor flow (incognito mode)
Open a private/incognito browser tab (clears all cookies and localStorage). Open DevTools → Network → filter for gtag or collect requests. Load your site. Confirm that before clicking Accept, no personalized GA hits fire (you should see at most a small cookieless ping with ep.consent_mode=q1 parameter, which is the denied-state ping).
Check 2: Accept flow
Click Accept on the banner. Confirm that gtag('consent', 'update') is called (visible in DevTools → Console if you log it, or in the dataLayer events visible via GTM debugger). Confirm that full GA sessions start.
Check 3: Returning visitor (no banner)
Reload the page in the same browser session (non-incognito). The banner should not reappear. DevTools → Application → Local Storage should show your consent key with value accepted.
Check 4: Decline flow
In incognito, click Decline. Reload the page. Confirm the banner does not reappear (choice is persisted). Confirm no _ga cookies are set (DevTools → Application → Cookies).
What happens to your AdSense revenue with consent denied?
This is the practical question every site owner cares about. With ad_storage: denied:
- Google still serves ads — but non-personalized ads (NPA) only
- NPA rates are 40–70% lower than personalized ad RPMs, depending on niche and geography
- For non-EEA traffic (India, US, most of Asia), consent mode doesn't change ad behavior — personalized ads fire by default for non-regulated regions
- For EEA traffic specifically: if fewer than 30% of your EEA users accept (typical for straightforward "Accept / Decline" banners), expect a significant portion of EEA revenue to drop to NPA rates
The practical implication for most Indian-audience sites like stax.tools: the EEA traffic share is small (under 5%), so the revenue impact of strict consent implementation is minimal. For EU-focused sites, the impact is real and worth factoring into your CMP UX design.
The bottom line for site operators
Ship the six items above and you're in good shape for both the regulator's auditor and Google's reviewer. The full stack — Consent Mode v2 defaults, certified CMP, 3-button banner, updated privacy policy, cookie table, and withdraw mechanism — is under 200 lines of code for most small sites and costs nothing if you use Google's free CMP.
The alternative — ignoring compliance — isn't free either. AdSense can restrict your account to NPA-only ads without notice. GDPR regulators have become more active with small sites in 2025. And AdSense application reviewers now explicitly check for consent implementation before approving new publishers.
— Want a tool to test the cookies on your site? Try CookieStatus (third-party tool), or open DevTools → Application → Cookies on your site to audit what's being set and when.

Harshil
Developer & Founder, stax.tools
Harshil is the developer behind stax.tools, building privacy-first tools that run entirely in your browser.
More by Harshil →Found this useful?
Browse 235+ free privacy-first tools — no login, no uploads, instant results.