Consent Mode v2 on 28 Pages, a Cookie Banner on One

Our homepage has a cookie banner. Google Consent Mode v2 is wired into it properly: analytics and advertising storage are denied before the page does anything, granted only after the visitor clicks accept, and the choice is persisted so we do not ask again. We have opened that page and tested that banner more times than we can count. It works.

Then we stopped opening the homepage and started counting pages instead.

Thirty-three pages on this site load Google Analytics. Twenty-eight of them set consent to denied by default. Exactly one of them — the homepage — is able to ask the visitor to change that.

What Consent Mode v2 Actually Does

Consent Mode is a handshake in two parts. Before the tag does any measurement, you declare a default posture. Ours, sitting inline in the <head> of every page, denies everything:

gtag('consent', 'default', {
  'ad_storage': 'denied',
  'ad_user_data': 'denied',
  'ad_personalization': 'denied',
  'analytics_storage': 'denied',
  'wait_for_update': 500
});

The second part is the update call, which fires when a visitor consents. That call is the entire point of the first one. A default-deny with no path to an update is not a privacy feature — it is a measurement outage that happens to be compliant.

It is worth being precise about what "denied" means, because a lot of writing on this gets it wrong. Denied does not mean nothing is sent. GA4 still receives cookieless pings, so you keep seeing traffic in your reports and nothing looks broken. What you lose is the cookie: no reliable stitching of one visitor across pages or sessions, degraded attribution, and conversion modelling that only helps if you feed it enough consented data to model from. The dashboard stays populated. The numbers quietly stop meaning what you think they mean.

Finding One: The Banner Lives on One Page

The banner markup and its two click handlers exist only in index.html. Every blog post, every service page, every app page carries the deny-by-default snippet and no way to lift it.

Read that against how people actually arrive. Search traffic does not land on homepages. It lands on the article that answered the query, or the service page that matched the search. A visitor who arrives from Google onto one of our posts is denied by default and never shown a choice. They read, they leave, and their entire visit is measured cookielessly. If they navigate to the homepage mid-visit the banner finally appears — but a reader of one article has no reason to.

The sharper version of this problem is paid traffic. We run Google Ads pointed at service landing pages, not at the homepage. Those pages deny ad_storage and ad_user_data by default and cannot ask for either. That is ad spend landing on pages structurally incapable of attributing a conversion properly.

Finding Two: Five Pages With No Gate at All

The same count turned up the opposite failure. Five of the thirty-three pages — the most recently added app pages — load GA4 with no consent call whatsoever:

gtag('js', new Date());
gtag('config', 'G-T97BQ3VRV1');

No default, no deny, no update. Those pages fall back to the tag's unrestricted behaviour and set cookies immediately, for every visitor, with no banner anywhere in sight. One site, two opposite defects: twenty-eight pages that refuse to measure and cannot ask permission, and five that measure without asking at all.

Neither of these was a decision. Both are what happens when an analytics snippet is copied by hand into each new page and the copy source drifts over time.

Why This Survives Testing

Two things conspire to hide it.

This is the same lesson as our accessibility audit and our audit of hotlinked images: the defects that survive longest are the ones invisible from the seat you normally sit in. The fix is not to look harder. It is to stop looking and start counting.

Audit Yours by Counting, Not Looking

Three commands, run at the root of your site, will tell you in seconds what an afternoon of clicking will not. Compare the numbers:

# How many pages load the tag?
grep -rl "G-XXXXXXXXXX" --include='*.html' . | wc -l

# How many declare a consent default?
grep -rl "consent', 'default'" --include='*.html' . | wc -l

# How many can actually ask the visitor?
grep -rl 'id="cookieBanner"' --include='*.html' . | wc -l

All three should be the same number. If the second is lower than the first, some pages are tracking ungated. If the third is lower than the second, some pages are denying consent with no way to lift it. Ours read 33, 28, and 1.

On a site with a build step or a CMS this class of bug is largely designed out — the snippet lives in one layout and every page inherits it. On a hand-built static site, which this is, nothing enforces that. The remedy is the same either way: one consent implementation, included everywhere, never copied. We are consolidating ours into a single shared include and deleting twenty-eight hand-maintained copies, which also means the next change to it is one edit rather than twenty-eight.

What to Take From This

If you have a cookie banner and a Consent Mode setup, the question is not whether it works. It is on how many pages it works, and whether that number matches the number of pages carrying your tag. Check it from a private window, on a page that is not your homepage, arriving the way a stranger would.

And be suspicious of an analytics setup that has never looked broken. Consent Mode fails quietly by design: the reports stay full, the graphs keep their shape, and the only visible symptom is numbers that are subtly, unfalsifiably wrong. We do not know how much of our own traffic was measured without cookies before we counted, and we never will. That is precisely the problem with this kind of bug — it destroys the evidence of its own existence.

Naša naslovnica ima cookie banner. Google Consent Mode v2 na njoj je ispravno postavljen: analitički i reklamni storage odbijeni su prije nego stranica bilo što učini, odobreni tek nakon što posjetitelj klikne prihvaćam, a odabir se pamti da ne pitamo dvaput. Tu smo stranicu otvorili i taj banner testirali više puta nego što možemo izbrojati. Radi.

Onda smo prestali otvarati naslovnicu i počeli brojati stranice.

Trideset i tri stranice na ovom sajtu učitavaju Google Analytics. Dvadeset i osam njih postavlja privolu na odbijeno po defaultu. Točno jedna — naslovnica — može posjetitelja pitati da to promijeni.

Što Consent Mode v2 zapravo radi

Consent Mode je rukovanje u dva dijela. Prije nego tag obavi bilo kakvo mjerenje, deklarirate početno stanje. Naše, koje sjedi inline u <head> svake stranice, odbija sve:

gtag('consent', 'default', {
  'ad_storage': 'denied',
  'ad_user_data': 'denied',
  'ad_personalization': 'denied',
  'analytics_storage': 'denied',
  'wait_for_update': 500
});

Drugi dio je update poziv, koji se aktivira kad posjetitelj da privolu. Taj poziv je cijela svrha prvoga. Default-deny bez puta do updatea nije značajka privatnosti — to je prekid mjerenja koji je slučajno usklađen s propisima.

Vrijedi biti precizan oko toga što "odbijeno" znači, jer velik dio tekstova o ovome to pogrešno tumači. Odbijeno ne znači da se ništa ne šalje. GA4 i dalje prima pingove bez kolačića, pa u izvještajima nastavljate vidjeti promet i ništa ne izgleda pokvareno. Ono što gubite je kolačić: nema pouzdanog povezivanja jednog posjetitelja kroz stranice ili sesije, atribucija je degradirana, a modeliranje konverzija pomaže samo ako mu date dovoljno podataka s privolom iz kojih bi modeliralo. Dashboard ostaje pun. Brojevi tiho prestaju značiti ono što mislite da znače.

Nalaz prvi: banner živi na jednoj stranici

Markup bannera i njegova dva click handlera postoje samo u index.html. Svaki blog post, svaka stranica usluge, svaka stranica aplikacije nosi snippet koji odbija po defaultu i nikakav način da se to podigne.

Pročitajte to uz to kako ljudi zapravo dolaze. Promet s tražilica ne slijeće na naslovnice. Slijeće na članak koji je odgovorio na upit ili na stranicu usluge koja je odgovarala pretrazi. Posjetitelj koji s Googlea dođe na jedan od naših postova odbijen je po defaultu i nikad mu se ne ponudi odabir. Pročita, ode, i cijeli njegov posjet izmjeren je bez kolačića. Ako usred posjeta otvori naslovnicu, banner se konačno pojavi — ali čitatelj jednog članka nema razloga za to.

Oštrija verzija ovog problema je plaćeni promet. Vodimo Google Ads usmjeren na landing stranice usluga, ne na naslovnicu. Te stranice po defaultu odbijaju ad_storage i ad_user_data i ne mogu tražiti ni jedno ni drugo. To je oglasni budžet koji slijeće na stranice strukturno nesposobne ispravno atribuirati konverziju.

Nalaz drugi: pet stranica bez ikakve zaštite

Isto brojanje otkrilo je obrnuti propust. Pet od trideset i tri stranice — najnovije dodane stranice aplikacija — učitavaju GA4 bez ijednog consent poziva:

gtag('js', new Date());
gtag('config', 'G-T97BQ3VRV1');

Bez defaulta, bez odbijanja, bez updatea. Te stranice padaju na neograničeno ponašanje taga i postavljaju kolačiće odmah, svakom posjetitelju, bez bannera na vidiku. Jedan sajt, dva suprotna propusta: dvadeset i osam stranica koje odbijaju mjeriti i ne mogu pitati za dopuštenje, i pet koje mjere bez pitanja.

Ni jedno ni drugo nije bila odluka. Oboje je ono što se dogodi kad se analitički snippet ručno kopira u svaku novu stranicu, a izvor kopiranja s vremenom odluta.

Zašto ovo preživi testiranje

Dvije stvari se urote da to skriju.

To je ista lekcija kao iz naše revizije pristupačnosti i revizije hotlinkanih slika: propusti koji najdulje preživljavaju oni su nevidljivi sa stolice na kojoj inače sjedite. Rješenje nije gledati pažljivije. Rješenje je prestati gledati i početi brojati.

Revidirajte svoj brojanjem, ne gledanjem

Tri komande, pokrenute u korijenu sajta, reći će vam u nekoliko sekundi ono što poslijepodne klikanja neće. Usporedite brojeve:

# Koliko stranica učitava tag?
grep -rl "G-XXXXXXXXXX" --include='*.html' . | wc -l

# Koliko deklarira consent default?
grep -rl "consent', 'default'" --include='*.html' . | wc -l

# Koliko ih uopće može pitati posjetitelja?
grep -rl 'id="cookieBanner"' --include='*.html' . | wc -l

Sva tri broja trebaju biti ista. Ako je drugi manji od prvog, neke stranice prate bez zaštite. Ako je treći manji od drugog, neke stranice odbijaju privolu bez načina da se to podigne. Naši su bili 33, 28 i 1.

Na sajtu s build stepom ili CMS-om ova klasa bugova uglavnom je dizajnom onemogućena — snippet živi u jednom layoutu i svaka stranica ga nasljeđuje. Na ručno građenom statičnom sajtu, a ovaj je takav, to ništa ne nameće. Lijek je u oba slučaja isti: jedna implementacija privole, uključena svugdje, nikad kopirana. Našu konsolidiramo u jedan zajednički include i brišemo dvadeset i osam ručno održavanih kopija, što ujedno znači da je sljedeća izmjena jedan edit, a ne dvadeset i osam.

Što iz ovoga izvući

Ako imate cookie banner i Consent Mode postavku, pitanje nije radi li. Pitanje je na koliko stranica radi i odgovara li taj broj broju stranica koje nose vaš tag. Provjerite iz privatnog prozora, na stranici koja nije vaša naslovnica, dolazeći onako kako bi došao stranac.

I budite sumnjičavi prema analitičkoj postavci koja nikad nije izgledala pokvareno. Consent Mode po dizajnu tiho podbacuje: izvještaji ostaju puni, grafovi zadržavaju oblik, a jedini vidljivi simptom su brojevi koji su suptilno i neprovjerljivo pogrešni. Ne znamo koliko je našeg prometa izmjereno bez kolačića prije nego smo prebrojali, i nikad nećemo znati. To je upravo problem s ovakvom vrstom buga — uništava dokaz o vlastitom postojanju.

← Back to blog