Lab paint timeline

Lab paint timeline on a cold crawl: TTFB, FCP, LCP in ms - setup-specific, not field data.

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

At a glance the headline numbers for Lab paint timeline

Lab paint timeline on a cold crawl: TTFB, FCP, LCP in ms - setup-specific, not field data.

366ms
lab FCP
on the typical page
556ms
lab LCP
on the typical page
1.4s
1 in 4 pages exceed this
lab LCP
183,720
sites measured
phone field data

In the lab, the typical site paints its main content after 556ms.

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 lab paint timeline — fcp

0ms 63ms 125ms 188ms 250ms
200ms
0 30210 60420
0–249 250–499 500–749 750–999 1000–1249 1250–1499 1500–1749 1750+
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 lab paint timeline — fcp which level passes the INP most often

Lab paint timeline — fcpSitesPassing INPINP
0–249 60,420 91% 95ms
250–499 52,470 92% 99ms
500–749 23,166 93% 100ms
750–999 13,077 93% 102ms
1000–1249 8,650 93% 102ms
1250–1499 5,799 94% 102ms
1500–1749 4,011 93% 103ms
1750+ 16,127 92% 103ms
Good Needs Improvement Poor Faded rows: under 100 sites

Lab paint timeline — fcp 366ms. p75 776ms. p99 10.2s. At the low end (0–249ms): INP 95ms. At the high end (1750+ms): INP 103ms. 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 lab paint timeline — lcp

0ms 63ms 125ms 188ms 250ms
200ms
0 40835 81670
0–499 500–999 1000–1499 1500–1999 2000–2499 2500–2999 3000–3499 3500–3999 4000–4499 4500+
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 lab paint timeline — lcp which level passes the INP most often

Lab paint timeline — lcpSitesPassing INPINP
0–499 81,670 91% 96ms
500–999 37,049 93% 100ms
1000–1499 16,429 93% 102ms
1500–1999 8,795 93% 103ms
2000–2499 5,047 92% 103ms
2500–2999 3,067 93% 104ms
3000–3499 2,832 93% 102ms
3500–3999 3,214 94% 99ms
4000–4499 3,290 94% 100ms
4500+ 14,786 91% 104ms
Good Needs Improvement Poor Faded rows: under 100 sites

Lab paint timeline — lcp 556ms. p75 1.4s. p99 19.3s. At the low end (0–499ms): INP 96ms. At the high end (4500+ms): 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

These are lab numbers from our crawler: one cold load, one machine, one network profile. They are not what your visitors feel. That is what the field data on the rest of this site measures. What the lab gives you is a controlled comparison: identical conditions for every site, so a difference between two sites is a real difference between the pages.

Read the gaps. Lab LCP far worse than field LCP usually means caching and repeat visits carry the field numbers. The reverse usually means the crawler's connection is kinder than your visitors' phones.

How does this affect the Core Web Vitals?

Passing INP barely moves across the range: 91% at one end, 92% at the other. This signal does not separate passing sites from failing ones.

Related signals Total Blocking Time (lab) → Main-thread CPU (lab) → Document lifecycle (lab) → Chrome field data from 189,915 sites, representing millions of real page loads · How we measured
Live queries (5) — admin only
Query #1: 52.6 ms
SELECT COUNT(*) AS count,
            quantile_disc(m.synthetic.paint.ttfb, 0.10) AS p10,
            quantile_disc(m.synthetic.paint.ttfb, 0.25) AS p25,
            quantile_disc(m.synthetic.paint.ttfb, 0.50) AS p50,
            quantile_disc(m.synthetic.paint.ttfb, 0.75) AS p75,
            quantile_disc(m.synthetic.paint.ttfb, 0.90) AS p90,
            quantile_disc(m.synthetic.paint.ttfb, 0.99) AS p99
            FROM sites WHERE m.synthetic.paint.ttfb IS NOT NULL;
Query #2: 309.2 ms
SELECT COUNT(*) AS count,
            quantile_disc(m.synthetic.paint.fcp, 0.10) AS p10,
            quantile_disc(m.synthetic.paint.fcp, 0.25) AS p25,
            quantile_disc(m.synthetic.paint.fcp, 0.50) AS p50,
            quantile_disc(m.synthetic.paint.fcp, 0.75) AS p75,
            quantile_disc(m.synthetic.paint.fcp, 0.90) AS p90,
            quantile_disc(m.synthetic.paint.fcp, 0.99) AS p99
            FROM sites WHERE m.synthetic.paint.fcp IS NOT NULL;
Query #3: 263.5 ms
SELECT CASE WHEN m.synthetic.paint.fcp >= 0 AND m.synthetic.paint.fcp < 250 THEN 0 WHEN m.synthetic.paint.fcp >= 250 AND m.synthetic.paint.fcp < 500 THEN 1 WHEN m.synthetic.paint.fcp >= 500 AND m.synthetic.paint.fcp < 750 THEN 2 WHEN m.synthetic.paint.fcp >= 750 AND m.synthetic.paint.fcp < 1000 THEN 3 WHEN m.synthetic.paint.fcp >= 1000 AND m.synthetic.paint.fcp < 1250 THEN 4 WHEN m.synthetic.paint.fcp >= 1250 AND m.synthetic.paint.fcp < 1500 THEN 5 WHEN m.synthetic.paint.fcp >= 1500 AND m.synthetic.paint.fcp < 1750 THEN 6 WHEN m.synthetic.paint.fcp >= 1750 THEN 7 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.synthetic.paint.fcp IS NOT NULL GROUP BY bucket_idx;
Query #4: 323.0 ms
SELECT COUNT(*) AS count,
            quantile_disc(m.synthetic.paint.lcp, 0.10) AS p10,
            quantile_disc(m.synthetic.paint.lcp, 0.25) AS p25,
            quantile_disc(m.synthetic.paint.lcp, 0.50) AS p50,
            quantile_disc(m.synthetic.paint.lcp, 0.75) AS p75,
            quantile_disc(m.synthetic.paint.lcp, 0.90) AS p90,
            quantile_disc(m.synthetic.paint.lcp, 0.99) AS p99
            FROM sites WHERE m.synthetic.paint.lcp IS NOT NULL;
Query #5: 330.7 ms
SELECT CASE WHEN m.synthetic.paint.lcp >= 0 AND m.synthetic.paint.lcp < 500 THEN 0 WHEN m.synthetic.paint.lcp >= 500 AND m.synthetic.paint.lcp < 1000 THEN 1 WHEN m.synthetic.paint.lcp >= 1000 AND m.synthetic.paint.lcp < 1500 THEN 2 WHEN m.synthetic.paint.lcp >= 1500 AND m.synthetic.paint.lcp < 2000 THEN 3 WHEN m.synthetic.paint.lcp >= 2000 AND m.synthetic.paint.lcp < 2500 THEN 4 WHEN m.synthetic.paint.lcp >= 2500 AND m.synthetic.paint.lcp < 3000 THEN 5 WHEN m.synthetic.paint.lcp >= 3000 AND m.synthetic.paint.lcp < 3500 THEN 6 WHEN m.synthetic.paint.lcp >= 3500 AND m.synthetic.paint.lcp < 4000 THEN 7 WHEN m.synthetic.paint.lcp >= 4000 AND m.synthetic.paint.lcp < 4500 THEN 8 WHEN m.synthetic.paint.lcp >= 4500 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.synthetic.paint.lcp IS NOT NULL GROUP BY bucket_idx;
JSON file lookups (4)
20260625/meta.json 0.04 ms
20260625/types.json 0.62 ms
20260625/loaf-scripts.json 0.32 ms
20260625/menu.json 3.23 ms