Google Analytics loads before cookie consent? How to check and fix

Your banner appears, but analytics may already be running. How to catch cookies and requests sent before Accept, then make the tag wait, with a prompt for your AI.

· 7 min read

Your site has a cookie banner. It looks right, with Accept and Reject buttons, and a choice that gets remembered. But open the browser's cookie list on a first visit and _ga may already be there, before anyone has clicked anything. The Reject button may be changing nothing at all.

This is one of the most common gaps on sites built with AI tools, and it is invisible from the outside. Nothing breaks and the banner works as a piece of UI. It just isn't connected to the thing it claims to control.

This article is a technical guide, not legal advice. The rules depend on where you and your visitors are. If you serve people in the EU or UK, read what the regulators say or ask a lawyer about your specific setup.

Why the banner and the tracker end up disconnected

Analytics and the banner usually arrive in separate prompts, and each one does exactly what was asked.

"Add Google Analytics" pastes the tag into index.html or a root layout. The browser runs that tag as it reads the page. Weeks later, "add a cookie banner" creates a React component that shows two buttons and writes consent=accepted to localStorage. Nothing in that component tells the tag to wait, and it couldn't anyway: by the time React mounts the banner, the tag has already run.

Three variations of the same problem are worth knowing:

  • The tag lives in Google Tag Manager. The page source shows only the container, but the container still fires analytics on load unless its tags are set up to require consent.
  • Consent mode was added after the tag. Google says the default consent state must be set before any command that sends measurement data. If the order is wrong, the first hits go out as if nothing had been configured.
  • Only the first page is covered. In a single-page app, a route listener may send page views on its own, outside the code that checks the visitor's choice.

Why it matters: Article 5(3) of the ePrivacy Directive covers storing or reading information on a visitor's device, and the EDPB's guidelines on its technical scope reach past cookies to things like tracking pixels. Analytics generally isn't treated as strictly necessary, so the banner is meant to come first, not at the same time.

Check it yourself

This takes about three minutes in Chrome, Edge or Firefox. You need a private window, because a normal one remembers your earlier choice.

  1. Open a private window and open DevTools with F12 before you visit the site.
  2. Go to the Network tab and type collect in the filter box.
  3. Load your site. Do not touch the banner.
  4. Look for requests to google-analytics.com/g/collect or a regional address such as region1.google-analytics.com. If they appear, data is leaving before consent.
  5. Open Application → Cookies (in Firefox, Storage → Cookies) and pick your domain. Look for _ga and _ga_ followed by your measurement ID. Google's cookie documentation lists both, with a default lifetime of two years.

A quicker way to see the cookies is to paste this into the Console:

document.cookie.split('; ').filter(c => /^(_ga|_gcl|_fbp)/.test(c))

That covers Google Analytics, Google Ads and Meta Pixel. An empty array [] before you click is what you want. It only shows cookies scripts can read, so the Application tab remains the full picture.

Then test the buttons, each in a fresh private window:

  1. Click Reject, reload, and repeat the checks. Still nothing should appear, including on other pages you open.
  2. Click Accept. Now _ga and the collect requests should appear. If they don't, your fix has quietly switched analytics off, and your reports will show it as a traffic drop.

To see how the tag is installed, look at the HTML the server sends:

curl -s https://yourdomain.com | grep -oE "googletagmanager\.com/[^\"' ]+|connect\.facebook\.net[^\"' ]*|gtag\('consent'[^)]*"

A gtag/js address with no gtag('consent' line above it usually means the tag runs unconditionally. An empty result doesn't clear the site: the tag may be added by JavaScript later, which is why the browser test comes first.

One result can mislead you. If you see collect requests but no cookies, you may be using consent mode in its advanced form. Per Google's consent mode overview, advanced mode sends cookieless pings while consent is denied, and basic mode blocks the tags until the visitor responds. Whether those pings are acceptable for your audience is a legal question, not a technical one. If you'd rather not have to answer it, use basic behaviour.

Fix it

You have two reasonable approaches.

Don't load the tag until the visitor accepts. This is the simplest option and the easiest to verify. Remove the tag from index.html and load it from a function that runs after Accept, and on later visits if the stored choice is still "accepted".

Use consent mode with denied defaults. The tag stays on the page, but it starts with everything denied and is updated when the visitor accepts. The order is the important part, and Google's setup guide covers the details:

<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'
  });
</script>
<!-- the Google tag goes after this block -->

Consent mode doesn't show a banner by itself. You still need a banner that calls gtag('consent', 'update', ...) when the visitor decides.

If you use a consent tool such as Cookiebot, CookieYes or OneTrust, read how it handles blocking. Some setups stop scripts automatically, while others only display the banner and leave the wiring to you. Installing the tool doesn't prove the wiring exists, so run the checks above either way.

A few details are easy to miss:

  • Other scripts. Meta Pixel, Hotjar, TikTok and chat widgets need the same treatment as analytics.
  • Changing your mind. Under GDPR, withdrawing consent has to be as easy as giving it. Add a "Cookie settings" link in the footer that reopens the choice. When someone withdraws, also remove the cookies already set.
  • Your Content-Security-Policy. If you have one, it has to allow the analytics domains after the change. See the CSP guide for React and Vite.

A prompt for Lovable, Cursor or Claude Code:

Our cookie banner is not connected to our trackers. Fix that.

1. List every analytics, advertising and chat script the app loads,
   including anything in index.html, the root layout, Google Tag
   Manager and third-party widgets. Show me the list before changing
   anything.
2. Remove those scripts from anything that runs on page load. Create
   one function that loads them, and call it only when the visitor
   has accepted, either now or in a stored earlier choice.
3. Page view tracking on route changes must use the same check.
4. If the visitor rejects, load nothing. Keep the choice so the banner
   does not reappear on every page.
5. Add a "Cookie settings" link in the footer that reopens the banner.
   If the visitor withdraws consent, stop tracking and delete the
   cookies the trackers set.
6. Tell me how to verify this in a private window: which requests and
   cookies must be absent before Accept and after Reject, and which
   must appear after Accept.

After deploying, repeat the private-window test yourself. A banner that looks finished proves nothing, as you found out above.

Keep it from coming back

This problem returns quietly. Someone adds a chat widget that brings its own tracker, a new prompt regenerates the layout and restores the old tag, or a marketing person adds a pixel in Tag Manager without touching the code. Your banner keeps working the whole time.

Keep a short list of every third-party script the site is meant to run, and repeat the private-window test whenever that list changes. Your privacy policy has to name those services too, so the same list does two jobs.

ScanYourSite's GDPR and cookie check catches part of this for you. The free check opens your page in a real browser, names the trackers it finds, including ones added by Tag Manager, and flags them as a serious issue when no recognised consent tool is on the page. It also reports cookies your server sets on the first load while no consent tool is present, and missing privacy policy or terms links.

It's worth being clear about the limits. It doesn't click your banner, it doesn't read cookies that scripts set later, such as _ga, and it doesn't test whether a recognised consent tool actually holds the trackers back. A banner you built yourself may not be recognised at all. So the private-window test above is still the real proof.

The free plan checks one site weekly and sends a summary by email. Pro checks daily and alerts you as soon as a check finds trackers running without a consent tool.

To see what your site loads today: https://scanyoursite.app/?check=yourdomain.com

Check your own site in a minute

Free, no sign-up. You get a prioritised list of what’s wrong and a prompt you can paste back into Lovable, Bolt, Cursor or Claude Code.

Free, no sign-up. The basic check makes only the requests an ordinary browser would.

GDPR and cookies