Fonts per page

How many web fonts load and their over-the-wire weight.

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

At a glance the headline numbers for Fonts per page

How many web fonts load and their over-the-wire weight.

4
font count
on the typical page
154 KB
font weight
on the typical page
295 KB
1 in 4 pages exceed this
font weight
190,130
sites measured
phone field data

The typical page loads 4 web fonts weighing 154 KB.

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

Distribution & median INP site count and median INP at each level of fonts per page — n

0ms 63ms 125ms 188ms 250ms
200ms
0 13008 26016
0–0 1–1 2–2 3–3 4–4 5–5 6–6 7–7 8–8 9+
Good (≤200ms) Needs improvement Poor (>500ms) Site count
The State of Web Vitals · Q2 2026 · 189,915 sites · phone field datacorewebvitals.io/state-of-cwv
3

Passing INP by fonts per page — n which level passes the INP most often

Fonts per page — nSitesPassing INPINP
0–0 24,676 76% 106ms
1–1 14,426 89% 96ms
2–2 22,039 93% 95ms
3–3 26,016 93% 96ms
4–4 24,705 94% 97ms
5–5 19,833 94% 97ms
6–6 15,952 95% 99ms
7–7 10,945 95% 101ms
8–8 8,345 95% 101ms
9+ 23,193 93% 104ms
Good Needs Improvement Poor Faded rows: under 100 sites

Fonts per page — n 4. p75 6. p99 20. At the low end (0–0): INP 106ms. At the high end (9+): INP 104ms. computed

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

Distribution & median INP site count and median INP at each level of fonts per page — size

0ms 63ms 125ms 188ms 250ms
200ms
0 15952 31903
0–49 50–99 100–149 150–199 200–249 250–299 300–349 350–399 400–449 450–499 500–549 550+
Good (≤200ms) Needs improvement Poor (>500ms) Site count
The State of Web Vitals · Q2 2026 · 189,915 sites · phone field datacorewebvitals.io/state-of-cwv
5

Passing INP by fonts per page — size which level passes the INP most often

Fonts per page — sizeSitesPassing INPINP
0–49 23,243 91% 96ms
50–99 31,903 93% 95ms
100–149 25,550 94% 96ms
150–199 19,560 94% 97ms
200–249 14,234 95% 99ms
250–299 10,606 94% 102ms
300–349 8,746 94% 100ms
350–399 6,222 93% 104ms
400–449 4,823 93% 103ms
450–499 3,599 94% 104ms
500–549 2,566 93% 101ms
550+ 14,402 93% 104ms
Good Needs Improvement Poor Faded rows: under 100 sites

Fonts per page — size 154 KB. p75 295 KB. p99 1.4 MB. At the low end (0–49 KB): INP 96ms. At the high end (550+ KB): INP 104ms. computed

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

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

Every font face is a separate file, and most sites load one per weight and style. Three families with three weights each is nine downloads of render-path bytes. Text either waits for them or reflows as they land, one by one.

The audit is quick: which weights actually appear above the fold? A variable font collapses a whole family of weights into one file. A system font stack costs nothing at all.

Related signals Images per page → Iframe dimensions set → Image source mix → Page weight & requests → Chrome field data from 189,915 sites, representing millions of real page loads · How we measured
Live queries (4) — admin only
Query #1: 127.3 ms
SELECT COUNT(*) AS count,
            quantile_disc(m.fonts.total.n, 0.10) AS p10,
            quantile_disc(m.fonts.total.n, 0.25) AS p25,
            quantile_disc(m.fonts.total.n, 0.50) AS p50,
            quantile_disc(m.fonts.total.n, 0.75) AS p75,
            quantile_disc(m.fonts.total.n, 0.90) AS p90,
            quantile_disc(m.fonts.total.n, 0.99) AS p99
            FROM sites WHERE m.fonts.total.n IS NOT NULL;
Query #2: 115.6 ms
SELECT CASE WHEN m.fonts.total.n >= 0 AND m.fonts.total.n < 1 THEN 0 WHEN m.fonts.total.n >= 1 AND m.fonts.total.n < 2 THEN 1 WHEN m.fonts.total.n >= 2 AND m.fonts.total.n < 3 THEN 2 WHEN m.fonts.total.n >= 3 AND m.fonts.total.n < 4 THEN 3 WHEN m.fonts.total.n >= 4 AND m.fonts.total.n < 5 THEN 4 WHEN m.fonts.total.n >= 5 AND m.fonts.total.n < 6 THEN 5 WHEN m.fonts.total.n >= 6 AND m.fonts.total.n < 7 THEN 6 WHEN m.fonts.total.n >= 7 AND m.fonts.total.n < 8 THEN 7 WHEN m.fonts.total.n >= 8 AND m.fonts.total.n < 9 THEN 8 WHEN m.fonts.total.n >= 9 THEN 9 END AS bucket_idx, 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_pct
            FROM sites WHERE m.fonts.total.n IS NOT NULL GROUP BY bucket_idx;
Query #3: 301.5 ms
SELECT COUNT(*) AS count,
            quantile_disc(m.fonts.total.size, 0.10) AS p10,
            quantile_disc(m.fonts.total.size, 0.25) AS p25,
            quantile_disc(m.fonts.total.size, 0.50) AS p50,
            quantile_disc(m.fonts.total.size, 0.75) AS p75,
            quantile_disc(m.fonts.total.size, 0.90) AS p90,
            quantile_disc(m.fonts.total.size, 0.99) AS p99
            FROM sites WHERE m.fonts.total.size IS NOT NULL;
Query #4: 285.9 ms
SELECT CASE WHEN m.fonts.total.size >= 0 AND m.fonts.total.size < 50 THEN 0 WHEN m.fonts.total.size >= 50 AND m.fonts.total.size < 100 THEN 1 WHEN m.fonts.total.size >= 100 AND m.fonts.total.size < 150 THEN 2 WHEN m.fonts.total.size >= 150 AND m.fonts.total.size < 200 THEN 3 WHEN m.fonts.total.size >= 200 AND m.fonts.total.size < 250 THEN 4 WHEN m.fonts.total.size >= 250 AND m.fonts.total.size < 300 THEN 5 WHEN m.fonts.total.size >= 300 AND m.fonts.total.size < 350 THEN 6 WHEN m.fonts.total.size >= 350 AND m.fonts.total.size < 400 THEN 7 WHEN m.fonts.total.size >= 400 AND m.fonts.total.size < 450 THEN 8 WHEN m.fonts.total.size >= 450 AND m.fonts.total.size < 500 THEN 9 WHEN m.fonts.total.size >= 500 AND m.fonts.total.size < 550 THEN 10 WHEN m.fonts.total.size >= 550 THEN 11 END AS bucket_idx, 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_pct
            FROM sites WHERE m.fonts.total.size IS NOT NULL GROUP BY bucket_idx;
JSON file lookups (4)
20260625/meta.json 0.03 ms
20260625/types.json 0.68 ms
20260625/loaf-scripts.json 0.45 ms
20260625/menu.json 0.35 ms