Monitoring Core Web Vitals (LCP, CLS, INP) From Your Own Analytics
What are Core Web Vitals?
Core Web Vitals are the three real-user performance metrics Google uses as a ranking signal:
- LCP (Largest Contentful Paint) — how fast the main content renders. Good: under 2.5 s.
- CLS (Cumulative Layout Shift) — how much the page jumps around while loading. Good: under 0.1.
- INP (Interaction to Next Paint) — how responsive the page feels to clicks/taps. Good: under 200 ms. (INP replaced FID in 2024.)
Two more are often tracked alongside: TTFB (server response time) and FCP (first paint).
Lab data vs. field data
Tools like Lighthouse give you lab data — one run, on one machine. Useful, but it is not what your actual users experience. Field data (a.k.a. RUM, Real User Monitoring) measures Web Vitals from real visitors on real devices and networks. Google ranks on field data.
To get field data you need to collect it from real sessions — which is exactly what an analytics tracking script can do.
How to collect Web Vitals from real users
The browser exposes Web Vitals through the PerformanceObserver API. A tracking script subscribes to them and reports the values back:
import { onLCP, onCLS, onINP } from 'web-vitals';
onLCP((m) => track('web_vital', { name: 'LCP', value: m.value }));
onCLS((m) => track('web_vital', { name: 'CLS', value: m.value }));
onINP((m) => track('web_vital', { name: 'INP', value: m.value }));InsightsTrack's tracking script does this automatically — no extra setup. Every real session contributes its Web Vitals.
What the tracking script actually sends
Each metric arrives as a small event tied to the page and session, so you can slice performance the same way you slice traffic:
{
"event": "web_vital",
"properties": {
"name": "LCP",
"value": 2140,
"rating": "good",
"path": "/pricing",
"device_type": "mobile",
"connection": "4g"
}
}Two details make this data trustworthy. Metrics are reported on page hide, not on load — LCP and CLS can both change right up until the user leaves, so reporting early understates them. And they are sent with navigator.sendBeacon so the report survives the page being torn down, which is exactly the moment these values become final.
Querying your own Web Vitals
Because the metrics land in the same event table as everything else, p75 by page is one query:
SELECT path,
count(*) AS samples,
round(quantile_cont(value, 0.75)) AS p75_lcp
FROM events
WHERE event_name = 'web_vital'
AND properties->>'name' = 'LCP'
AND device_type = 'mobile'
AND timestamp >= current_date - 28
GROUP BY path
HAVING count(*) > 100
ORDER BY p75_lcp DESC
LIMIT 20;The HAVING clause is not optional. A p75 computed from nine samples is noise, and it will sort straight to the top of your "worst pages" list. See 12 SQL queries every dashboard needs for more in this shape.
Reading the numbers: use p75, not averages
Google scores Web Vitals at the 75th percentile of your traffic. Averages hide your slowest 25% of users (often mobile / slow networks). Always look at p75: "75% of my users had an LCP under X." InsightsTrack's Performance page scores each metric Good / Needs-Improvement / Poor against Google's thresholds at p75.
Turning metrics into fixes
- High LCP? Optimize your largest image/hero, preload critical assets, reduce server TTFB.
- High CLS? Set explicit width/height on images and embeds; avoid injecting content above existing content.
- High INP? Break up long JavaScript tasks, defer non-critical work, avoid heavy event handlers.
Catching regressions after a deploy
The reason to keep Web Vitals next to your traffic data is that it turns a vague question into a dated one. Plot p75 LCP by day and mark your deploys; a regression shows up as a step change, not a slow drift.
SELECT timestamp::DATE AS day,
round(quantile_cont(value, 0.75)) AS p75_lcp,
count(*) AS samples
FROM events
WHERE event_name = 'web_vital' AND properties->>'name' = 'LCP'
AND timestamp >= current_date - 60
GROUP BY 1 ORDER BY 1;Watch for the pattern where p75 LCP degrades and conversion on the same pages drops a day later. That correlation is the argument that gets performance work prioritised, and you can only make it when both numbers live in the same place. Funnel analysis is where to look next when it happens.
Field data will disagree with Lighthouse
Expect it, and do not treat it as a bug:
- Lighthouse is one run on one simulated device and network. Your field p75 spans real phones on real connections.
- Lighthouse cannot see logged-in pages, personalised content, or third-party scripts that only load in production.
- Google ranks on field data (CrUX), not lab data.
Use Lighthouse to diagnose a page you already know is slow from field data. Use field data to decide which page that is.
Frequently asked questions
What is the difference between lab and field data?
Lab data comes from a synthetic run on fixed hardware and network — repeatable, good for debugging. Field data comes from real visitors on real devices. Google ranks on field data, so lab scores are a development tool, not the thing being measured.
Why use p75 instead of an average?
An average hides the tail, and the tail is where bad experiences live. One slow visitor in four is a real problem that a mean comfortably conceals. Google itself assesses at the 75th percentile, so measuring the same way keeps your numbers comparable.
Does INP replace FID?
Yes. INP became the responsiveness Core Web Vital in March 2024. FID measured only the first interaction's input delay; INP considers latency across the whole visit, which reflects what users actually feel.
Do I need Chrome UX Report data if I collect my own?
No. CrUX is useful for competitive comparison and covers only Chrome users above a traffic threshold. Your own field data covers every browser, updates immediately, and can be segmented by page and device in ways CrUX cannot.
Why do my Web Vitals differ from PageSpeed Insights?
PageSpeed's lab score is one simulated load on throttled hardware; your field data is thousands of real loads. They answer different questions, and a good lab score with poor field data usually points at real-world network or device variation.
Why monitor it from your own analytics
Monitoring Web Vitals inside the same tool you already use for traffic means you can correlate performance with behaviour: did a deploy regress LCP? Did a slow page hurt conversions? And because it is self-hosted and cookieless, you collect this real-user data without sending anything to a third party.
See live Core Web Vitals (LCP, CLS, INP, TTFB) scored against Google's thresholds in the InsightsTrack demo. Related: which metrics actually matter and reading bounce rate correctly.
Try InsightsTrack free
Open-source, self-hosted, privacy-first analytics — explore the live demo, no install required.
Open live dashboard