Total Blocking Time (lab)

Total Blocking Time on the lab crawl.

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

At a glance the headline numbers for Total Blocking Time (lab)

Total Blocking Time on the lab crawl.

16ms
on the typical site
half of sites sit at or below
172ms
1 in 4 sites exceed this
the top quarter
6.5s
the heaviest 1%
the long tail
185,486
sites measured
phone field data

The typical site blocks the main thread for 16ms during the lab load.

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

Total Blocking Time (lab) the value at each percentile across all sites

0ms
p10
0ms
p25
16ms
p50
172ms
p75
709ms
p90
6,461ms
p99

Total Blocking Time (lab) 16ms. p75 172ms. p99 6.5s. 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

Total Blocking Time counts the parts of long tasks where a click would have waited. It is the lab stand-in for INP: a crawler does not click, so instead we measure how often the main thread was too busy to answer if someone had.

High TBT with good field INP usually means real visitors interact after the dust settles. The risk lives in the early click, the visitor who taps the menu while the tag pile is still booting. The fix list is the script list: less of it, later, in smaller pieces.

Related signals Main-thread CPU (lab) → Lab paint timeline → Document lifecycle (lab) → Chrome field data from 189,915 sites, representing millions of real page loads · How we measured
Live queries (2) — admin only
Query #1: 432.6 ms
SELECT COUNT(*) AS count,
            quantile_disc(m.synthetic.tbt_ms, 0.10) AS p10,
            quantile_disc(m.synthetic.tbt_ms, 0.25) AS p25,
            quantile_disc(m.synthetic.tbt_ms, 0.50) AS p50,
            quantile_disc(m.synthetic.tbt_ms, 0.75) AS p75,
            quantile_disc(m.synthetic.tbt_ms, 0.90) AS p90,
            quantile_disc(m.synthetic.tbt_ms, 0.99) AS p99
            FROM sites WHERE m.synthetic.tbt_ms IS NOT NULL;
Query #2: 14.3 ms
SELECT CASE WHEN m.synthetic.tbt_ms >= 0 AND m.synthetic.tbt_ms < 100 THEN 0 WHEN m.synthetic.tbt_ms >= 100 AND m.synthetic.tbt_ms < 200 THEN 1 WHEN m.synthetic.tbt_ms >= 200 AND m.synthetic.tbt_ms < 300 THEN 2 WHEN m.synthetic.tbt_ms >= 300 AND m.synthetic.tbt_ms < 400 THEN 3 WHEN m.synthetic.tbt_ms >= 400 AND m.synthetic.tbt_ms < 500 THEN 4 WHEN m.synthetic.tbt_ms >= 500 AND m.synthetic.tbt_ms < 600 THEN 5 WHEN m.synthetic.tbt_ms >= 600 AND m.synthetic.tbt_ms < 700 THEN 6 WHEN m.synthetic.tbt_ms >= 700 AND m.synthetic.tbt_ms < 800 THEN 7 WHEN m.synthetic.tbt_ms >= 800 THEN 8 END AS bucket_idx, COUNT(*) AS n,
            quantile_disc(crux."phone".cls, 0.5) AS median,
            COUNT(*) FILTER (WHERE crux."phone".cls IS NOT NULL AND crux."phone".cls <= 0.1) * 1.0 / NULLIF(COUNT(*) FILTER (WHERE crux."phone".cls IS NOT NULL), 0) AS good_pct
            FROM sites WHERE m.synthetic.tbt_ms IS NOT NULL GROUP BY bucket_idx;
JSON file lookups (4)
20260625/meta.json 0.06 ms
20260625/types.json 0.72 ms
20260625/loaf-scripts.json 0.49 ms
20260625/menu.json 0.17 ms