ETag present

Whether responses carry ETag validators.

Field data PhoneDesktopAll Scope All sites Q2 2026 edition · Phone field outcomes
Metric LCP INP CLS
1

At a glance the headline numbers for ETag present

Whether responses carry ETag validators.

83.4%
of sites have it
158,569 of 190,130
median LCP with it
median LCP without
190,130
sites measured
phone field data

83.4% of sites serve ETag validators.

The State of Web Vitals · Q2 2026 · 189,915 sites · phone field datacorewebvitals.io/state-of-cwv
2

ETag present sites that have it vs sites that don't

ETag present
83.4%

83.4% of sites send ETag headers (158,569 of 190,130). With send: INP 100ms, 92.1% pass. Without: INP 95ms, 90.2% pass. computed

The State of Web Vitals · Q2 2026 · 189,915 sites · phone field datacorewebvitals.io/state-of-cwv
3

Why this matters for the Core Web Vitals, and where to start fixing it

An ETag is a validator. When a cached file expires, the browser can ask the server whether it changed and get a tiny 304 Not Modified back instead of the whole file. Without a validator, an expired file is downloaded again in full.

Validators matter most for the in-between caching strategies: short TTLs with frequent revisits. For hashed, immutable assets they are redundant because the file never changes under its name. One thing to watch on multi-server setups: default ETags can differ per server, and a mismatched ETag silently turns every revalidation into a full download.

Related signals Last-Modified present → Uncompressed text responses → Main CDN → HTTP protocol → Chrome field data from 189,915 sites, representing millions of real page loads · How we measured
Live queries (1) — admin only
Query #1: 90.1 ms
SELECT m.headers.has_etag AS val, COUNT(*) AS n,
            quantile_disc(crux."phone".inp, 0.5) AS median,
            COUNT(*) FILTER (WHERE crux."phone".inp IS NOT NULL AND crux."phone".inp <= 200) * 1.0 / NULLIF(COUNT(*) FILTER (WHERE crux."phone".inp IS NOT NULL), 0) AS good,
            COUNT(*) FILTER (WHERE crux."phone".inp IS NOT NULL AND crux."phone".inp > 200 AND crux."phone".inp <= 500) * 1.0 / NULLIF(COUNT(*) FILTER (WHERE crux."phone".inp IS NOT NULL), 0) AS ni,
            COUNT(*) FILTER (WHERE crux."phone".inp IS NOT NULL AND crux."phone".inp > 500) * 1.0 / NULLIF(COUNT(*) FILTER (WHERE crux."phone".inp IS NOT NULL), 0) AS poor
            FROM sites WHERE 1=1 GROUP BY m.headers.has_etag;
JSON file lookups (4)
20260625/meta.json 0.04 ms
20260625/types.json 0.56 ms
20260625/loaf-scripts.json 0.45 ms
20260625/menu.json 0.14 ms