Lab paint timeline
Lab paint timeline on a cold crawl: TTFB, FCP, LCP in ms - setup-specific, not field data.
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.
In the lab, the typical site paints its main content after 556ms.
Distribution & median INP site count and median INP at each level of lab paint timeline — fcp
Passing INP by lab paint timeline — fcp which level passes the INP most often
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
Distribution & median INP site count and median INP at each level of lab paint timeline — lcp
Passing INP by lab paint timeline — lcp which level passes the INP most often
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
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.
Chrome field data from 189,915 sites, representing millions of real page loads. How we measured.
Live queries (5) — admin only
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;
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;
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;
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;
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;