How Many Websites Track You Before Consent? 2026 Study
Websites tracking before consent: 1 in 3 EU-domain homepages that showed a cookie banner had already set tracking cookies before any click. Data from 370 sites.
One in three. On 9 October 2026 we loaded 174 European-domain homepages in a fresh browser and never touched the cookie banner. Of the 78 that showed a consent banner, 33.3% had already written a first-party analytics or advertising cookie (such as _ga or _fbp) before anyone made a choice. 64.1% had already contacted a known tracking host.
Across all 174 EU-domain sites, 35.1% set a first-party tracking cookie on the bare page load, and 61.5% contacted a tracker. In a second, global sample of 196 homepages, the share setting tracking cookies before consent was 60.7%.
These are the method, the results by banner, consent platform and country domain, the trackers that fire most, and a script you can run to check your own site the same way. It's a measurement, not a legal judgement. Whether a specific cookie needs consent depends on its purpose and your jurisdiction.
Methodology
| Item | Detail |
|---|---|
| EU sample | Tranco list 94GG2, ranks 1,001–100,000, restricted to EU/EEA country-code domains (.de, .fr, .it, .pl, .nl, .es, .eu and the rest). 300 drawn at random (seed 20261009), and 174 valid after excluding unreachable sites, bot challenges and pages under 50 words |
| Global sample | The 219 homepages from our accessibility statistics study (ranks 1,001–50,000, seed 20261003). 196 loaded fully in the browser |
| Browser | Chromium 123, fresh profile per site (no cookies, no stored consent), desktop viewport 1366×900, en-US locale. The EU sample used timezone Europe/Berlin |
| Procedure | Load the homepage, wait for load plus 6 seconds, never click or scroll, then read every cookie in the browser and every host contacted |
| Classifier | BugViso's privacy audit (analyze_privacy): tracker cookie name signatures, known tracker hosts and consent-platform hosts, with Google Consent Mode v2 taken into account |
| Date | 9 October 2026 |
Three limits matter for interpreting the results:
- Vantage point. The crawler connected from Bangladesh. Many consent platforms show banners only to visitors geolocated in the EU or UK, so some sites likely served us their non-EU experience. That's why the headline uses only sites that showed a banner to us: they were asking for consent and had already tracked anyway, whatever the region logic.
- Third-party cookies were allowed, as in standard Chrome at the time. Browsers that block them, like Safari and Firefox, would show fewer third-party cookies. That's why the headline counts first-party analytics and advertising cookies, which every browser accepts.
- Homepages only, with no interaction. Tracking that starts on scroll or on inner pages isn't counted, so these numbers are a floor.
Headline Results
| Measurement (no consent given) | EU-domain sample (174) | Global sample (196) |
|---|---|---|
| Showed a visible consent banner | 78 (44.8%) | 53 (27.0%) |
| Set a first-party analytics/ad cookie | 61 (35.1%) | 119 (60.7%) |
| Set any tracking cookie (first- or third-party) | 65 (37.4%) | 123 (62.8%) |
| Contacted a known tracker host | 107 (61.5%) | 158 (80.6%) |
| Set no cookies at all | 18 (10.3%) | 12 (6.1%) |
| BugViso privacy score (median) | 96 | 76 |
Sites that showed a banner but tracked anyway
| Among sites with a visible banner | EU-domain (78) | Global (53) |
|---|---|---|
| First-party tracking cookie already set | 26 (33.3%) | 24 (45.3%) |
Of which Google Analytics _ga | 14 | 18 |
| Known tracker host already contacted | 50 (64.1%) | 41 (77.4%) |
This is the clearest finding. A banner on screen means the site is asking for permission. When the analytics cookie already exists, the answer no longer changes what happened on the first page view.
The EU-domain sample was clearly more careful than the global one: almost twice as likely to show a banner, and markedly less likely to set tracking cookies. European regulators have spent years enforcing consent rules, and it shows. A third of bannered sites still jump the gun, though.
⚠️ Contacting a tracker host is not automatically a violation. Google Tag Manager often loads before consent by design, and under Consent Mode v2 Google tags can load without writing cookies until the visitor accepts. BugViso's classifier accounts for this. When Consent Mode's default denies storage and no tracking cookies were written, Google hosts aren't counted. That applied on 19 EU-domain sites.
Which Trackers Fire Before Consent
Share of sites that contacted each host on the bare load:
| Tracker host | EU-domain | Global |
|---|---|---|
| googletagmanager.com | 48% | 72% |
| doubleclick.net | 25% | 44% |
| google-analytics.com | 22% | 35% |
| googlesyndication.com | 21% | 18% |
| cloudflareinsights.com | 14% | 25% |
| facebook.net | 13% | 23% |
| bing.com | 7% | 15% |
| linkedin.com | 6% | 13% |
| criteo.com | 6% | 7% |
| clarity.ms | 5% | 12% |
Cloudflare Web Analytics (cloudflareinsights.com) is on BugViso's tracker list because it's third-party analytics, but it's designed to work without cookies. Many legal assessments treat cookieless, aggregate analytics differently, so a hit for that host is a prompt to document it rather than a red flag.
The most common pre-consent cookies in the EU sample were Google Analytics _ga (38 sites), Meta's _fbp (17), Google's IDE ad cookie (14), Google Ads _gcl_au (13), and Criteo's cto_ cookies (11). The median offending site set 4 tracking cookies. The worst set 34.
Results by Consent Platform
BugViso detects a consent management platform (CMP) when the page requests one of its known hosts. We detected one on 39 EU-domain sites:
| CMP (detected by host) | EU-domain sites | First-party tracking cookie before consent |
|---|---|---|
| OneTrust | 17 | 7 |
| Usercentrics | 11 | 2 |
| Cookiebot | 7 | 3 |
| iubenda | 3 | 3 |
| Other | 1 | 1 |
The groups are too small to rank vendors, and that isn't the point. Every one of these platforms can block tags until consent. Whether it does depends on how the site wired its tags to it. When tracking fires before consent on a CMP-equipped site, the cause is almost always configuration, typically a tag manager that loads analytics on "All Pages" instead of on a consent trigger, or a hard-coded pixel in the theme.
Google Consent Mode v2 was set (a consent default command in the data layer) on 45 EU-domain sites (25.9%). 19 of those still wrote first-party tracking cookies. That's consistent with region-specific defaults: Consent Mode lets sites deny storage only for EU/EEA regions, so a visitor geolocated elsewhere gets "granted". It also shows that "we have Consent Mode" and "we don't set cookies before consent" are different claims.
Results by Country Domain
| ccTLD | Sites | Any tracking cookie before consent |
|---|---|---|
| .de | 42 | 10 (24%) |
| .fr | 19 | 8 (42%) |
| .pl | 15 | 4 (27%) |
| .it | 14 | 8 (57%) |
| .nl | 11 | 5 (45%) |
| .cz | 10 | 3 (30%) |
| .es | 8 | 2 (25%) |
| .se | 8 | 2 (25%) |
With samples this small, a single site moves a percentage by 5 to 12 points, so read this as "German domains in our sample were the most cautious" and nothing stronger.
How Banners Behave
Of the 78 EU-domain banners, 45 sat at the bottom of the screen, 21 covered the whole viewport (a consent wall), 7 were centred modals and 5 sat at the top. All but one were position: fixed. That matters for performance: fixed banners don't push content, so they rarely cause layout shift. The exceptions are covered in our guide to cookie banners without layout shift.
Check Your Own Site the Same Way
This script reproduces the procedure: a fresh profile, no clicks, a wait, then every cookie and tracker host listed and classified. It needs Playwright (pip install playwright && playwright install chromium).
#!/usr/bin/env python3
"""preconsent_scan.py: list cookies and tracker requests a page triggers BEFORE any consent click.
Usage:
pip install playwright && playwright install chromium
python3 preconsent_scan.py https://example.com [--wait 6] [--tz Europe/Berlin] [--json out.json]
Opens a fresh browser profile (no stored consent), loads the page, never clicks anything,
waits, then reports every cookie (first/third party, classified) and every known tracker host
contacted. Exit code 1 when tracking cookies or tracker requests fired pre-consent.
Not legal advice: it tells you what happened, not whether it was lawful.
"""
import argparse, asyncio, json, sys, time
from urllib.parse import urlsplit
from playwright.async_api import async_playwright
TRACKER_HOSTS = (
"google-analytics.com", "googletagmanager.com", "doubleclick.net", "googlesyndication.com",
"googleadservices.com", "facebook.net", "facebook.com", "connect.facebook.net", "hotjar.com",
"clarity.ms", "bing.com", "linkedin.com", "licdn.com", "ads-twitter.com", "tiktok.com",
"pinterest.com", "snapchat.com", "criteo.com", "criteo.net", "taboola.com", "outbrain.com",
"adroll.com", "quantserve.com", "scorecardresearch.com", "hubspot.com", "hs-analytics.net",
"hs-scripts.com", "segment.com", "segment.io", "mixpanel.com", "amplitude.com", "fullstory.com",
)
CMP_HOSTS = ("cookiebot.com", "onetrust.com", "cookielaw.org", "usercentrics.eu", "didomi.io",
"trustarc.com", "iubenda.com", "termly.io", "cookieyes.com", "osano.com", "consensu.org",
"quantcast.com", "axeptio.eu", "complianz.io", "civicuk.com")
ANALYTICS = ("_ga", "_gid", "_gat", "__utm", "_hjSession", "_hjid", "_clck", "_clsk", "ajs_", "amplitude_id",
"mp_", "_pk_id", "_pk_ses", "__hstc", "__hssc", "hubspotutk", "_uetsid", "_uetvid", "_mkto_trk")
ADVERTISING = ("_fbp", "_fbc", "_gcl_", "_ttp", "li_fat_id", "_pin_unauth", "cto_bundle", "_scid", "_rdt_uuid")
# Short, generic names that only mean "ad tracker" when an ad network sets them on its own domain.
AD_NETWORK_NAMES = {"IDE", "test_cookie", "MUID", "fr", "bcookie", "lidc", "personalization_id", "NID"}
def site(host):
parts = (host or "").lower().lstrip(".").split(".")
return ".".join(parts[-3:] if len(parts) > 2 and parts[-2] in ("co", "com", "org", "gov", "ac") else parts[-2:])
def match(host, domains):
h = (host or "").lower().lstrip(".")
return next((d for d in domains if h == d or h.endswith("." + d)), None)
def classify(name, domain, third_party):
if name.startswith(ANALYTICS):
return "analytics"
if name.startswith(ADVERTISING) or (third_party and name in AD_NETWORK_NAMES):
return "advertising"
if third_party and match(domain, TRACKER_HOSTS):
return "tracking (3rd-party host)"
return "3rd-party, unknown: check" if third_party else "1st-party, unknown: check"
async def scan(url, wait, tz):
async with async_playwright() as pw:
browser = await pw.chromium.launch()
ctx = await browser.new_context(locale="en-US", timezone_id=tz) if tz else await browser.new_context(locale="en-US")
page = await ctx.new_page()
hosts = set()
page.on("request", lambda r: hosts.add(urlsplit(r.url).hostname or ""))
await page.goto(url, wait_until="load", timeout=45000)
await page.wait_for_timeout(wait * 1000) # let tag managers and CMPs run
gcm = await page.evaluate("""() => { const dl = window.dataLayer || []; let d = null;
for (const e of dl) { if (e && e.length !== undefined && e[0] === 'consent' && e[1] === 'default') d = Object.assign(d || {}, e[2]); }
return d; }""")
cookies = await ctx.cookies()
await browser.close()
me = site(urlsplit(url).hostname)
rows = []
for c in cookies:
third = site(c["domain"]) != me
rows.append({"name": c["name"], "domain": c["domain"], "party": "3rd" if third else "1st",
"category": classify(c["name"], c["domain"], third),
"days": round((c["expires"] - time.time()) / 86400) if c["expires"] > 0 else "session"})
trackers = sorted({match(h, TRACKER_HOSTS) for h in hosts if match(h, TRACKER_HOSTS)})
cmps = sorted({match(h, CMP_HOSTS) for h in hosts if match(h, CMP_HOSTS)})
return {"url": url, "cookies": rows, "tracker_hosts": trackers, "consent_platforms": cmps, "consent_mode_default": gcm}
def report(r):
bad = [c for c in r["cookies"] if c["category"] in ("analytics", "advertising", "tracking (3rd-party host)")]
print(f"\n{r['url']}")
print(f" consent platform seen : {', '.join(r['consent_platforms']) or 'none detected'}")
print(f" Consent Mode default : {json.dumps(r['consent_mode_default']) if r['consent_mode_default'] else 'not set'}")
print(f" cookies before consent: {len(r['cookies'])} total, {len(bad)} tracking")
for c in sorted(r["cookies"], key=lambda c: (c["category"], c["name"])):
flag = "✗" if c in bad else " "
print(f" {flag} {c['name'][:32]:32s} {c['party']} {c['category']:30s} {c['domain'][:28]:28s} {c['days']}")
print(f" tracker hosts contacted: {', '.join(r['tracker_hosts']) or 'none'}")
return bool(bad or r["tracker_hosts"])
if __name__ == "__main__":
ap = argparse.ArgumentParser()
ap.add_argument("url")
ap.add_argument("--wait", type=int, default=6, help="seconds to wait after load (default 6)")
ap.add_argument("--tz", help="browser timezone, e.g. Europe/Berlin (some banners are region-targeted)")
ap.add_argument("--json", help="also write the raw result to this file")
a = ap.parse_args()
result = asyncio.run(scan(a.url, a.wait, a.tz))
if a.json:
json.dump(result, open(a.json, "w"), indent=2)
sys.exit(1 if report(result) else 0)Run it from a machine (or VPN exit) in the region you're testing. The banner your EU visitors see may not be the one shown elsewhere. Cookies marked "unknown: check" aren't in the signature list. Look up each one in your CMP's cookie scan or the vendor's documentation before assuming it's necessary.
How BugViso Measures Pre-Consent Tracking
The script mirrors what BugViso's Privacy & Compliance audit does on every scan. The page is loaded in Chromium without interacting with the consent banner (BugViso's interaction simulation deliberately skips cookie and consent elements, so it never clicks "Accept"). It then reads every cookie and every host contacted on that bare load. The audit reports:
- Tracking cookies set before consent, with names, first- or third-party, category (analytics, advertising, functional or essential), persistence, and
Secure/SameSiteflags - Tracker hosts contacted, matched against a list of 45 known analytics and ad domains
- The consent platform detected, from 15+ CMP signatures including OneTrust, Cookiebot, Usercentrics, Didomi, iubenda and CookieYes
- Google Consent Mode v2 state: whether a default is set and whether storage is denied, so compliant Consent Mode setups aren't flagged
- A privacy score from 0 to 100: −6 per tracking cookie and −4 per tracker host, with an extra −15 when a consent platform is present but tracking fired anyway
You can run a free BugViso scan to see your site's pre-consent cookies. For the step-by-step fix, see the cookie compliance scanner guide and the GDPR website compliance checklist. The security and privacy checks page lists every signature.
FAQ
What percentage of websites set cookies before consent?
In our 196-site global sample, 60.7% of homepages set a first-party analytics or advertising cookie before any consent choice. Among 174 EU country-domain homepages it was 35.1%, and among EU-domain sites that showed a consent banner, 33.3%.
Is setting Google Analytics cookies before consent illegal in the EU?
Under Article 5(3) of the ePrivacy Directive, storing non-essential cookies requires prior consent, and analytics cookies are generally treated as non-essential. The EDPB's guidelines on the technical scope of Art. 5(3) also cover tracking pixels and similar techniques. National rules and exemptions vary, so get legal advice for your situation.
Does having a cookie banner make a site compliant?
No. A banner only collects a choice. Compliance depends on tags actually waiting for that choice. A third of the EU-domain sites in our study that showed a banner had already set tracking cookies.
Why do some sites show no banner?
Either they set no non-essential cookies, or they show banners only to visitors from regions where the law requires it. Because our crawler connected from outside the EU, some sites likely served us their non-EU experience.
Can I reproduce this study?
Yes. The sampling frame, seeds, wait time and classifier are described above, and the script reproduces the per-site measurement. Please cite "BugViso Pre-Consent Tracking Study 2026 (174 EU-domain and 196 global homepages, October 2026)".
Conclusion
A consent banner doesn't prove consent. On a third of the EU-domain sites that showed one, analytics cookies were already written before the visitor could answer, so test your own bare page load from your visitors' region, or let a BugViso scan list every cookie that fires before the click.
See where your site stands
Run a free BugViso audit for SEO, speed, accessibility and AI search readiness — with fixes you can ship today.