31 tools· updated sep 2026

GA4 consent mode: the sessions your banner hides, measured against Search Console clicks

Marek.

  • measurement
  • ad-platforms
  • field-notes

GA4 consent mode is how a site tells the Google tag what the visitor allowed: store cookies, send cookieless pings, or send nothing. This site runs the basic version, and since 12 October 2026 it loads no Google tag and sends nothing to Google Analytics before you choose or after you decline. In August I set consent mode up for a European store selling car parts on a hosted e-commerce platform. There a denied default with no banner left eight days of zero GA4 sessions while Search Console kept counting clicks. This post covers the mechanism, both implementations and the numbers from both sites.

  • What it is. Four consent types, two commands: default before config on every page, update when the visitor clicks. Analytics reads analytics_storage.
  • Basic or advanced. Basic keeps the tag off the page until consent; advanced loads it and pings without cookies while denied. This site ran advanced until 12 October 2026 and runs basic since.
  • The gap. Store, 16 to 23 August: no GA4 session rows against 178 to 241 Search Console impressions and 1 to 6 clicks a day. 24 August to 1 September: 229 GA4 sessions against 367 clicks.
  • Behavioral modeling. GA4 fills report gaps with modeled data only above thresholds: 1,000 denied events a day for 7 days and 1,000 consenting users a day on 7 of 28 days, and meeting them does not guarantee eligibility. Basic is not eligible at all. Both sites' volumes, read on 4 and 15 September, were small next to those bars.
  • The rule. Every number gets its instrument, window and blind spot. The second instrument is Search Console, pulled for the same days through this site's Search Console API review.

Consent mode carries the visitor's answer to the Google tag as four signals, each set to granted or denied: ad_storage, analytics_storage, ad_user_data and ad_personalization. The first two control cookies, and Analytics reads analytics_storage to decide whether it may set its cookie. Whether GA4 measures anything before consent depends on the implementation, not on the signals. Under basic, nothing leaves the browser until the visitor accepts. Under advanced, cookieless pings leave from the first page view.

Order matters as much as the values. Google's consent guide wants the default command on every page "before any commands that send measurement data" and warns that consent defaults won't work when the consent code is called out of order. On an advanced gtag.js site that ordering is the first thing I look for in the source, before any of the checks further down.

The difference is whether the Google tag exists on the page before the visitor answers. Basic, per the concepts page, keeps Google tags from loading until the visitor interacts with the consent banner. Advanced loads them when the page opens and, while consent is denied, sends cookieless pings. Per About consent mode, those pings may include a timestamp, the user agent, the referrer, a flag for ad-click information such as a GCLID in the URL, the consent state as Boolean values, a random number and the ID of the consent management platform.

Basic consent modeAdvanced consent mode
Google tag before the clickNot loadedLoaded on page open
Data before the clickNone, not even the consent stateCookieless pings
After DeclineStill nothingCookieless pings continue
After AcceptTag loads and measures with cookiesUpdate to granted, cookies from then on
Conversion and key event modeling"a general model""an advertiser-specific model"
GA4 behavioral modelingNot eligiblePossible above thresholds, if Google judges the property eligible

What this site does before you click

No Google tag and no Analytics hits. Until you answer the banner, the page loads no gtag.js and sends nothing to Google Analytics, and Decline keeps it that way. Accept loads the tag once, with one config call. The choice is stored in the browser, so on the next page load the tag either loads straight away or stays off.

The pattern looks like this. It is a simplified sketch, not the production file:

function loadAnalytics() {
  if (window.gtag) return;
  window.dataLayer = window.dataLayer || [];
  window.gtag = function () { window.dataLayer.push(arguments); };
  gtag('consent', 'default', {
    ad_storage: 'denied',
    ad_user_data: 'denied',
    ad_personalization: 'denied',
    analytics_storage: 'granted'
  });
  gtag('js', new Date());
  gtag('config', 'G-XXXXXXX');
  const s = document.createElement('script');
  s.async = true;
  s.src = 'https://www.googletagmanager.com/gtag/js?id=G-XXXXXXX';
  document.head.appendChild(s);
}

// stored choice: 'granted' loads the tag, 'denied' or nothing loads nothing
if (storedChoice === 'granted') loadAnalytics();
// Accept: store 'granted', then loadAnalytics(). Decline: store 'denied', load nothing.

Read it from the bottom. Nothing runs unless the stored choice is granted, and the <script> element for gtag.js is only created inside loadAnalytics(), so a visitor who declines or never answers never downloads the library. That is what makes it basic. Inside the function, the check on window.gtag stops a second call from loading the tag twice. The consent default comes before config, as the consent guide requires, with the three ad signals denied and analytics_storage granted, because by the time this code runs the visitor has already said yes. The ad types never change; this site runs no ads. After Accept, the hits that leave carry gcs=G101: Analytics cookies allowed, Ads cookies not.

What the sketch leaves out is the awkward case: a browser where storage is unavailable, so there is no stored choice to read. The production code has a fallback for that; the sketch does not.

Until 12 October this site ran the advanced version. gtag.js arrived on every page load, every first visit started denied, and the first page view left as a cookieless ping. The banner said "Analytics stays off until you accept" the whole time. Under advanced that was half true: the cookie stayed off, the tag was loaded and pinging. The banner text did not change in the switch. The behavior changed to match it.

For scale, not comparison, the 15 September read, taken under the advanced setup, shows 59 GA4 users here since 25 July against 6,931 Search Console impressions and 10 clicks since launch: different windows, traffic and units.

Consent Mode v2 added two signals to the original ad_storage and analytics_storage. Per Simo Ahava, ad_user_data asks whether the visitor consents to their personal data being used for advertising, and ad_personalization whether their data may be used for remarketing. Neither touches Analytics reports. They matter when the same tag serves Google Ads to visitors in the European Economic Area, where Google's EEA update says "you need to pass through end-user consent choices to Google"; for the upload side of conversions, see our Google Ads API review. Here the three ad signals stay denied. On the store, which was about to run Shopping, the banner came first: without granted consent, purchases would not be counted in full, and a campaign would have nothing to optimize on.

It depends on which version you want and where your tags live. For advanced with gtag.js, call gtag('consent', 'default', ...) on every page before any config or event command, with the four types set to denied, then call gtag('consent', 'update', ...) the moment the visitor answers the banner. For basic, keep the tag off the page until the visitor accepts, then load it with the consent state already set, as in the sketch above.

With Google Tag Manager, the states come from a consent management platform template or your own template built on Tag Manager's consent APIs, setDefaultConsentState and updateConsentState, fired on the Consent Initialization trigger. Google's consent guide says not to use gtag('consent','update',...) in their place, because "gtag commands are queued after all other pending messages and may not be processed before the next event begins".

Advanced has two options worth setting. wait_for_update is "a millisecond value to control how long to wait before data is sent", so the first ping waits for a banner that loads asynchronously. Region defaults let you "set defaults for specific regions, and then set a different default for all other regions". A consent management platform runs both commands and keeps the record; the store used a hosted one fired from the container.

GTM consent mode: the same two states, set through a template

In Tag Manager the mechanism is the same, a default and an update, but they come from a template and a trigger, with a per-tag setting on top. Per Tag Manager consent mode support, every web container includes a Consent Initialization - All Pages trigger by default, and it fires before all other tags, so that is where the default and the CMP tag belong. Google's own tags carry built-in consent checks; everything else gets a per-tag "Require additional consent for tag to fire" setting.

The store's container history is this post in short: a default-denied consent tag on 11 August, the day measurement went live; the CMP tag that could turn denied into granted on 24 August. In between, the default was the only consent state any visitor had.

The gap: a store where Search Console counted clicks on days GA4 counted nothing

Search Console clicks and GA4 sessions will not match even on a healthy site. Search Console counts clicks from Google Search; GA4 counts visits from every channel, and only the visits it was allowed to measure. On this store the gap went further: for eight days GA4 counted nothing at all.

Both instruments were read on 4 September: GA4 through the Data API, window 6 August to 4 September, last day in progress; Search Console through its API, 28 days from 6 August, with 1 September the last day carrying data. GA4 had no rows from 16 to 23 August, while Search Console shows 178 to 241 impressions and 1 to 6 clicks a day for those dates. People arrived and the instrument was not listening. Counting resumed on 24 August, the day the banner went live.

Day (2026)GA4 sessionsSearch Console clicksSearch Console impressions
16 to 23 Augno rows1 to 6 a day178 to 241 a day
24 Aug11211,100
25 Aug33481,843
26 Aug40722,162
27 Aug39632,155
28 Aug30471,797
29 Aug2127931
30 Aug1323884
31 Aug23421,103
1 Sept1924923
24 Aug to 1 Sept22936712,898

GA4: all channels. Search Console: by date, Google Search only.

Four things the table does not say. The columns are different units: Search Console counts "How often someone clicked a link from Google to your site" (metrics article), while a GA4 session is any consented visit from any channel, and Organic Search was 213 of the 270 sessions in the 30-day window; 229 against 367 is roughly six in ten, not a consent rate. Second, 264 of the 270 sessions fall in the 12 days from 24 August: a 30-day baseline says 9 a day, the 12 measured days say 22. Third, the Search Console jump on 24 August is not the banner; a sitemap index for the whole catalogue went in on 23 August. Fourth, Search Console hides too: by date the 28 days hold 409 clicks, by query only 30 appear across 1,970 rows, and the other 379, 92.7 percent, sit behind "anonymized (rare) results are omitted from the table, but are included in the chart totals" (troubleshooting article).

My first draft of the client report made two mistakes a reviewer caught. It turned GA4's zero add-to-cart events and zero purchases for 24 August to 4 September into "this traffic does not buy", though GA4 counts consenting visitors and I had not read the store's order panel since 11 August. And it set the best Search Console day, 72 clicks, against a ten-day average of GA4 sessions. Peak against mean is not a comparison.

Behavioral modeling: the thresholds a small site is far from

Advanced consent mode is sold on modeling: denied pings feed a model that fills the gap in reports. The behavioral modeling article sets the bar: consent mode on all pages, "at least 1,000 events per day with analytics_storage='denied' for at least 7 days", and "at least 1,000 daily users sending events with analytics_storage='granted' for at least 7 of the previous 28 days". The same article says meeting these prerequisites "doesn't guarantee eligibility". Blended is the reporting identity that shows modeled data in reports; it does not change what the tag collects. Modeled data never reaches "Audiences", "Retention reports" or the BigQuery export. Conversion modeling for Ads is a separate model: per the concepts page, basic gets "a general model" and advanced "an advertiser-specific model", as in the table above.

For scale, not as an eligibility test: the store averaged about 22 GA4 sessions a day, all channels, from 24 August to 4 September 2026, with the last day still in progress, and this site had 59 users between 25 July and 15 September, while it still ran advanced. Sessions are not daily consenting users, so neither figure measures eligibility, but both are small next to a bar of 1,000 consenting users a day. Under basic this site is not eligible for behavioral modeling at all. I have no October read of its traffic, so I make no claim about what the switch on 12 October cost.

Google requires consent signals for EEA traffic; whether the law requires a banner is a separate question this post does not answer. Google's EEA update says that to keep using its tags "for measurement, and for ad personalization, and remarketing features" you must collect consent from EEA users and share consent signals with Google.

The EU user consent policy requires "legally valid consent to: the use of cookies or other local storage where legally required; and the collection, sharing, and use of personal data for personalization of ads". Consent mode does not obtain consent; a banner does. It reports the answer, and when nothing is reported Google assumes "a consented state unless a specific choice has been made, though there may be regional behavioral differences for specific areas like the EEA, Switzerland, and the UK" (About consent mode, linked above).

First decide what you want off. To stop Analytics, pause or remove the GA4 tag and keep the banner. To stop the advanced pings, switch to basic: keep the Google tag off the page until the visitor accepts, which is what this site did on 12 October. To remove consent mode itself, remove the consent signals, the gtag('consent', ...) calls or the consent settings in your CMP's Google integration. I would not remove the whole CMP: it is what collects the visitor's choice, and tags that wait for consent depend on it.

With no consent values set, Google's Ads help calls the state consented, with regional differences possible for the EEA, Switzerland and the UK. The consent guide's starting point is "By default, no consent mode values are set." Turning consent mode off does not turn measurement off; it turns the question off. I would not do it, and the store is the reason: its gap was not consent mode but half of it, a denied default with no update path. Deleting the default would probably have restored the numbers too, at the price of measuring every EEA visitor without asking.

No single checker exists; I use four views of the same handshake.

View source first. On an advanced gtag.js site, search for gtag('consent'; the default block must sit before gtag('config'. On a basic site like this one, what matters is what loads before the click, and the source alone does not show that. A Tag Manager site shows only the container snippet. Either way this step only tells you which of the next checks you need.

Tag Assistant for the sequence. Google's verification article has you "select the earliest Consent event" at tagassistant.google.com, then in the tag's Consent tab "check the 'On-page Default' column. Ensure it's set to 'Denied'", and after the click the 'On-page Update' column for 'Granted'. On the store that test showed the interim state agreed on 11 August: a Default column and no Update until the consent banner went live on 24 August.

The network tab for what left. Each hit carries the state in its query string as gcs, where per Simo Ahava x "stands for consent to Google Ads cookies" and y "stands for consent to Google Analytics cookies": G100 none, G110 Ads only, G101 Analytics only, G111 both. Under basic there is no gcs to read before the click, because there is no hit. The acceptance check of this site's banner on 12 October found no request for gtag.js or Analytics before a choice or after Decline, then one tag and one config after Accept, with hits carrying G101. The choice held after a refresh.

The slow fourth check is GA4 Admin. Per Verify and update consent settings, "under Data collection and modification, click Consent settings"; the page shows "the percentage of your website traffic and conversions coming from the EEA" and "may alert you to potential issues with your consent signals", with "48-72 hours" of lag. It is the only check that reports a share of traffic rather than one browser.

What I do with GA4 numbers now

Name the instrument and the window, including the last day with data: on 4 September, Search Console ended on 1 September while GA4 had a partial 4 September. Name the blind spot: a denied visitor for GA4, an anonymized query for Search Console, an untagged event for both.

Compare the same days. Inside GA4, the Search Console link adds a "Google Organic Search Traffic" report that "Displays landing pages with associated Search Console and Analytics metrics"; a landing page with clicks and no sessions is the gap, one row at a time. For anything scripted I pull the Search Console API first.

Treat a zero as a question: zero purchases in GA4 is a reason to open the order panel, not a finding about demand. This site's 59 users by 15 September is what consenting visitors amounted to here; under basic, a visitor who declines leaves no trace in GA4 at all. The banner promises "No ads, no cross-site tracking" either way. What consent mode changes is what I am allowed to believe about the count.

The verdict

A measurement note, so no RUNNING or TESTED label. Consent mode does what the docs say: the tag stores nothing until told it may, and in the advanced version sends cookieless pings that become modeled report data only on a property Google judges eligible. This site now runs basic, so before the click there is nothing to ping. The failure I keep meeting is a default without an update, a report that forgets its instrument, and a zero read as a fact about the world. Search Console was counting the whole time.