The Consent Illusion: Who Really Runs Luxembourg’s Web

After GDPR, Luxembourg’s web sprouted cookie banners — but only on about one site in three. Meanwhile nearly three in four .lu sites quietly load Google. By parsing the raw HTML of 83,000 website-years, I map the trackers they embed, the banners they show, and the handful of foreign companies the local web depends on.
Published

June 30, 2026

In my first three posts I asked what Luxembourg’s web says — its languages, its topics, and who gets served in which language. This time I ask something different: how is the web built, and who controls it?

Every time you open a website, your browser quietly fetches resources from other companies’ servers — analytics scripts, advertising pixels, fonts, maps, embedded videos. You never see them, but many of them see you. So I parsed the raw HTML of every .lu website-year in the sample and recorded three things: the third parties each site connects you to, whether it shows a cookie-consent banner, and who owns those third parties.

NoteThe Dataset

8,061 Luxembourg websites in 2024, parsed from raw HTML. The median site reaches out to 3 third-party domains, 71.5% embed at least one Google service — yet only 31.2% show a cookie-consent banner.

Whose Servers Are You Really Talking To?

When a Luxembourg website loads, where do its third-party requests point? I mapped every embedded domain I could identify to the country of its owner. A .lu third party counts as local; everything else is foreign infrastructure the site leans on.

Owner country of identified third parties, 2013–2024

Show code
sov_years = sovereignty['years']
shares = sovereignty['country_share_identified']

fig = go.Figure()

for country in ['Other', 'LU', 'EU', 'US']:
    fig.add_trace(go.Scatter(
        x=sov_years,
        y=shares[country],
        name=country_names[country],
        mode='lines',
        stackgroup='one',
        line=dict(color=country_colors[country], width=0),
        fillcolor=country_colors[country],
        hovertemplate=f"<b>{country_names[country]}</b><br>%{{y:.1f}}% of identified third parties<extra></extra>",
    ))

fig.update_layout(
    height=460,
    margin=dict(t=20, r=20, b=100, l=60),
    plot_bgcolor='white',
    paper_bgcolor='white',
    xaxis=dict(title='Year', dtick=1, gridcolor='#eee', zerolinecolor='#eee'),
    yaxis=dict(title='% of identified third parties', ticksuffix='%',
               range=[0, 100], gridcolor='#eee', zerolinecolor='#eee'),
    legend=dict(orientation='h', y=-0.28, x=0.5, xanchor='center'),
    hovermode='x unified',
)

fig.show(config={'displayModeBar': False})

Note: Shares are computed over third parties that could be attributed to a known owner; about 30% of all third-party connections in 2024 could not be attributed and are excluded from this chart.

TipKey Findings

Luxembourg’s web runs on someone else’s infrastructure. Of the third parties I could identify in 2024, 86.1% are US-owned against just 2.9% local. Only 6.2% of .lu sites embed any Luxembourg-hosted third party at all.

For a country that talks about digital sovereignty, the web tells a blunter story: open almost any .lu site and you are, within milliseconds, talking to California.

The Companies Inside Luxembourg’s Web

Which specific companies sit inside the most sites?

Most-embedded third-party companies (2024)

Show code
top = list(reversed(top_entities))
labels = [e['entity'] for e in top]
vals = [e['pct_sites'] for e in top]
bar_colors = [country_colors.get(e['country'], '#9aa0a6') for e in top]

fig = go.Figure(go.Bar(
    y=labels,
    x=vals,
    orientation='h',
    marker=dict(color=bar_colors),
    text=[f'{v:.0f}%' for v in vals],
    textposition='outside',
    customdata=[[country_names.get(e['country'], e['country']),
                 'tracker' if e['tracker'] else 'functional'] for e in top],
    hovertemplate='<b>%{y}</b><br>%{x:.1f}% of sites<br>%{customdata[0]} · %{customdata[1]}<extra></extra>',
))

fig.update_layout(
    height=max(420, len(top) * 28),
    margin=dict(t=20, r=70, b=50, l=160),
    plot_bgcolor='white',
    paper_bgcolor='white',
    xaxis=dict(title='% of websites embedding this company', ticksuffix='%',
               gridcolor='#eee', zerolinecolor='#eee'),
    yaxis=dict(tickfont=dict(size=11)),
    showlegend=False,
)

fig.show(config={'displayModeBar': False})

Note: Bars are colored by owner country ( US, EU, Luxembourg, other). A site counts once per company.

TipKey Findings

One company stands apart. Google reaches 71.5% of all .lu sites — more than four times as common as any other company, and nearly ten times the reach of Meta (7.5%), the largest social tracker after it. Crucially, much of Google’s reach is not ad-tracking but fonts, maps and reCAPTCHA — services a developer adds without a second thought. Yet even embedding Google Fonts hands the visitor’s IP address to Google, which a German court ruled a GDPR violation in 2022. On Luxembourg’s web, you don’t have to be advertised to in order to be exposed; you just have to load the page.

Do Essential Services Track You Too?

Reusing the sector labels from my topic-modelling post, I can ask whether the sites you have to use — your commune, your doctor, your child’s crèche — handle your data more carefully than the market does.

Share of sites embedding a US-owned tracker, by sector (2024)

Show code
sectors = [s for s in by_sector if s['n_sites'] >= 5]
sectors_sorted = sorted(sectors, key=lambda s: s['us_tracker_pct'])

names = [s['sector'] for s in sectors_sorted]
vals = [s['us_tracker_pct'] for s in sectors_sorted]
essential = set(ess_vs_mkt['essential_sectors'])
bar_colors = ['#2166ac' if n in essential else '#b2182b' for n in names]

fig = go.Figure(go.Bar(
    y=names,
    x=vals,
    orientation='h',
    marker=dict(color=bar_colors),
    text=[f'{v:.0f}%' for v in vals],
    textposition='outside',
    hovertemplate='<b>%{y}</b><br>%{x:.1f}% embed a US tracker<extra></extra>',
))

fig.update_layout(
    height=max(420, len(names) * 30),
    margin=dict(t=20, r=70, b=50, l=160),
    plot_bgcolor='white',
    paper_bgcolor='white',
    xaxis=dict(title='% of sites embedding a US-owned tracker', ticksuffix='%',
               gridcolor='#eee', zerolinecolor='#eee'),
    yaxis=dict(tickfont=dict(size=11)),
    showlegend=False,
)

fig.show(config={'displayModeBar': False})

Note: essential services (Public Services, Healthcare, Childcare), market-driven and other sectors. “US-owned tracker” = an analytics/advertising/social/tag-manager domain owned by a US company.

TipKey Findings

Needing a service does not protect you. Essential-service sites embed a US tracker on 46.0% of pages — slightly more than market-driven sites (43.6%), not less. Childcare is the most tracked sector of all (60% embed a US tracker, 90% load Google), even as it became one of the least multilingual. Public-service sites show the most cookie banners (58%) — the institutions most bound by the law are the ones that ask — but they still hand you to the same foreign platforms.

Methodology

This analysis parses the raw HTML behind the same CommonCrawl sample used across the series — no new models are trained; the value is in reading what the markup reveals about a site’s infrastructure.

1. Third-Party Extraction
For each website-year I parse every archived page and collect the external hosts it loads resources from — src attributes (<script>, <img>, <iframe>, <source>), <link> hrefs, and absolute URLs inside inline scripts. Navigation links (<a href>) are deliberately excluded so “follow us on Facebook” is not miscounted as an embedded third party. A third party is any host whose registrable domain (eTLD+1) differs from the site’s own. I also flag named cookie-consent platforms and HTTPS.
2. Entity & Country Mapping
Each third-party domain is matched against a curated, version-controlled entity map of the dominant web companies, giving an owning entity, owner country (US / EU / LU / Other), and a category. Any .lu third party counts as local. Trackers (analytics, advertising, social, tag managers, marketing) are separated from functional infrastructure (CDNs, fonts, payments, maps, video). Domains not in the map are reported as unidentified and never assumed to be trackers — a deliberately conservative count, and the reason the sovereignty chart shows only the share that could be attributed.
3. Aggregation
Per website-year I compute third-party counts, the owner-country mix, and big-tech reach, inner-joined to the language sample (same universe as the other posts) and to the BERTopic sector mapping for the sector and essential-vs-market cuts.

Note: This measures third parties declared in the archived HTML, not live network traffic. CommonCrawl archives only a handful of pages per site and captures markup before JavaScript runs, so scripts injected at runtime (and many banners) are undercounted — every tracker figure here is a lower bound.

Citation

For attribution, please cite this work as:

Garbers, J. (2026, June). The Consent Illusion: Who Really Runs Luxembourg's Web.
Retrieved from https://github.com/julio-garbers/blog/tree/main/web_trackers_lux

BibTeX:

@misc{garbers2026consent,
  author = {Garbers, Julio},
  title = {The Consent Illusion: Who Really Runs Luxembourg's Web},
  url = {https://github.com/julio-garbers/blog/tree/main/web_trackers_lux},
  year = {2026}
}