At a glance the headline numbers for Shift direction
Which way the shifting content moved.
54.0% of layout shifts push content downwards.
The shift direction mix who uses what, and how fast each group loads
Shift direction. On the fleet: 54.0% down, 46.0% lateral. 54.4% of sites use at least one down.
Passing INP per bucket every category and count level at once - color is the pass rate
Each row is a category, each column its own count bucket (few on the left, many on the right); the cell is the share of those sites passing INP.
No category moves the INP pass rate much, however many a site ships. computed
Few vs many - does quantity cost INP? the pass rate with few vs many of each category
Per category: the pass rate among pages with FEW of it (hollow ring) against pages with MANY (solid dot), worst trend first. Thin buckets are excluded from the endpoints.
Quantity barely moves INP here. The worst trend is Lateral, at 0 points. computed
Why this matters for the Core Web Vitals, and where to start fixing it
The direction of a shift is a fingerprint of its cause. Content that moves down means something above it arrived late: an unsized image, an injected banner, an ad slot that grew. Content that moves up means something collapsed or disappeared, like a dismissed notice that did not leave a placeholder. Sideways movement is rarer. It usually comes from a scrollbar appearing, centering changes, or a font swapping to a wider face.
Most pages shift downwards because most late content lands near the top. If your shifts point another way, trust the fingerprint: it narrows the suspect list before you open a single trace.
Chrome field data from 189,915 sites, representing millions of real page loads. How we measured.
Live queries (2) — admin only
SELECT 1 AS ok FROM site_metric_bags LIMIT 0;
WITH flat AS (
SELECT b.cat, b.n, b.size, s.crux."phone".inp AS cwv_val
FROM site_metric_bags b
JOIN sites s ON s.origin = b.origin
WHERE b.path = 'cls.direction'
AND b.cat IS NOT NULL
),
totals AS (
SELECT cat,
SUM(n) AS fleet_n,
SUM(size) AS fleet_size,
COUNT(*) FILTER (WHERE n IS NOT NULL) AS sample,
COUNT(*) FILTER (WHERE n > 0) AS with_any,
quantile_disc(n, 0.95) AS p95,
COUNT(*) AS n_rows
FROM flat
GROUP BY cat
),
widths AS (
SELECT *,
GREATEST(1, CAST(round(COALESCE(p95, 0)) AS INTEGER)) AS cap,
LEAST(GREATEST(1, CAST(round(COALESCE(p95, 0)) AS INTEGER)), 12 - 1) AS regular_buckets
FROM totals
),
widths2 AS (
SELECT *,
GREATEST(1, CAST(ceil(cap * 1.0 / regular_buckets) AS INTEGER)) AS width
FROM widths
),
binned AS (
SELECT f.cat, f.cwv_val, w.fleet_n, w.fleet_size, w.sample, w.with_any, w.width, w.regular_buckets,
CASE WHEN f.n IS NULL THEN NULL
ELSE LEAST(CAST(FLOOR(f.n * 1.0 / w.width) AS INTEGER), w.regular_buckets)
END AS bucket_idx
FROM flat f
JOIN widths2 w ON f.cat = w.cat
)
SELECT cat, fleet_n, fleet_size, sample, with_any, width, regular_buckets,
bucket_idx,
COUNT(*) AS n,
quantile_disc(cwv_val, 0.5) AS median,
COUNT(*) FILTER (WHERE cwv_val IS NOT NULL) AS total_cwv,
COUNT(*) FILTER (WHERE cwv_val IS NOT NULL AND cwv_val <= 200) AS good
FROM binned
WHERE bucket_idx IS NOT NULL
GROUP BY cat, fleet_n, fleet_size, sample, with_any, width, regular_buckets, bucket_idx
ORDER BY cat, bucket_idx;