Document lifecycle (lab)
Lab document lifecycle: DOM interactive, DOM complete, load event.
At a glance the headline numbers for Document lifecycle (lab)
Lab document lifecycle: DOM interactive, DOM complete, load event.
Distribution & median LCP site count and median LCP at each level of document lifecycle (lab) — load
Passing LCP by document lifecycle (lab) — load which level passes the LCP most often
Document lifecycle (lab) — load 676ms. p75 1.4s. p99 24.1s. At the low end (0–499ms): LCP 1.3s. At the high end (3000+ms): LCP 2.1s. computed
Why this matters for the Core Web Vitals, and where to start fixing it
The document lifecycle is the old way of measuring pages, and it still says useful things. DOM interactive marks the HTML fully parsed. DOM complete waits for the subresources. The load event is the official end of loading, and everything that listens for it (analytics, widgets, third-party tags) starts there.
A long gap between interactive and complete means resource weight, not markup. These milestones do not map onto user experience the way the vitals do, which is why they were replaced. But a page with a slow lifecycle does not produce fast vitals.
How does this affect the Core Web Vitals?
Document lifecycle (lab) correlates with the LCP. Where the load event is low, 90% of sites pass the LCP. Where it is high, 62% do. The decline is gradual. There is no point where sites suddenly start failing.
Chrome field data from 189,915 sites, representing millions of real page loads. How we measured.
Live queries (4) — admin only
SELECT COUNT(*) AS count,
quantile_disc(m.synthetic.document.dom_interactive, 0.10) AS p10,
quantile_disc(m.synthetic.document.dom_interactive, 0.25) AS p25,
quantile_disc(m.synthetic.document.dom_interactive, 0.50) AS p50,
quantile_disc(m.synthetic.document.dom_interactive, 0.75) AS p75,
quantile_disc(m.synthetic.document.dom_interactive, 0.90) AS p90,
quantile_disc(m.synthetic.document.dom_interactive, 0.99) AS p99
FROM sites WHERE m.synthetic.document.dom_interactive IS NOT NULL;
SELECT COUNT(*) AS count,
quantile_disc(m.synthetic.document.dom_complete, 0.10) AS p10,
quantile_disc(m.synthetic.document.dom_complete, 0.25) AS p25,
quantile_disc(m.synthetic.document.dom_complete, 0.50) AS p50,
quantile_disc(m.synthetic.document.dom_complete, 0.75) AS p75,
quantile_disc(m.synthetic.document.dom_complete, 0.90) AS p90,
quantile_disc(m.synthetic.document.dom_complete, 0.99) AS p99
FROM sites WHERE m.synthetic.document.dom_complete IS NOT NULL;
SELECT COUNT(*) AS count,
quantile_disc(m.synthetic.document.load, 0.10) AS p10,
quantile_disc(m.synthetic.document.load, 0.25) AS p25,
quantile_disc(m.synthetic.document.load, 0.50) AS p50,
quantile_disc(m.synthetic.document.load, 0.75) AS p75,
quantile_disc(m.synthetic.document.load, 0.90) AS p90,
quantile_disc(m.synthetic.document.load, 0.99) AS p99
FROM sites WHERE m.synthetic.document.load IS NOT NULL;
SELECT CASE WHEN m.synthetic.document.load >= 0 AND m.synthetic.document.load < 500 THEN 0 WHEN m.synthetic.document.load >= 500 AND m.synthetic.document.load < 1000 THEN 1 WHEN m.synthetic.document.load >= 1000 AND m.synthetic.document.load < 1500 THEN 2 WHEN m.synthetic.document.load >= 1500 AND m.synthetic.document.load < 2000 THEN 3 WHEN m.synthetic.document.load >= 2000 AND m.synthetic.document.load < 2500 THEN 4 WHEN m.synthetic.document.load >= 2500 AND m.synthetic.document.load < 3000 THEN 5 WHEN m.synthetic.document.load >= 3000 THEN 6 END AS bucket_idx, COUNT(*) AS n,
quantile_disc(crux."phone".lcp, 0.5) AS median,
COUNT(*) FILTER (WHERE crux."phone".lcp IS NOT NULL AND crux."phone".lcp <= 2500) * 1.0 / NULLIF(COUNT(*) FILTER (WHERE crux."phone".lcp IS NOT NULL), 0) AS good_pct
FROM sites WHERE m.synthetic.document.load IS NOT NULL GROUP BY bucket_idx;