Core Web Vitals Pro
Capture the five Core Web Vitals — LCP, CLS, INP, FCP, and TTFB — on real user loads. One web_vital event per metric per page load, with the metric name, value, rating, and pathname so you can segment by page.
Install the peer dep
The web-vitals capture path is dynamic-imported, so it only lands in the bundle when enabled. You need web-vitals as a peer dependency:
npm install web-vitalsIf the peer dep isn’t installed, the extension silently no-ops. Nothing breaks, but no web_vital events fire. Turn on debug mode to verify.
Enable
init("proj_xxx", { extensions: { webVitals: true } })
// or, in React:
<Analytics projectId="proj_xxx" extensions={{ webVitals: true }} />What fires
One web_vital event per captured metric per page load:
| Property | Example | Notes |
|---|---|---|
metric | LCP | One of LCP, CLS, INP, FCP, TTFB. |
value | 2453.12 | Rounded to 2 decimals, sent as a string. Milliseconds for time metrics; unitless for CLS. |
rating | good | One of good, needs-improvement, poor. Buckets come from the web-vitals library. |
id | v4-1712345678-123 | Unique per measurement. Dedup if you aggregate server-side. |
pathname | /pricing | The page the metric was measured on. Segment by this for per-page CWV. |
The five metrics
- LCP(Largest Contentful Paint) — when the biggest visible element finished rendering. The main “feels fast” metric. Target: under 2.5s.
- CLS (Cumulative Layout Shift) — unitless score for how much visible content jumps around during load. Target: under 0.1.
- INP (Interaction to Next Paint) — worst-case response time to user interactions across the session. Replaced FID in 2024. Target: under 200ms.
- FCP (First Contentful Paint) — when any content first appears. Earlier signal than LCP; not part of the official Core Web Vitals but useful for diagnosing slow starts.
- TTFB (Time to First Byte) — how long the network round-trip to your origin took. Diagnostic rather than ranking signal.
Sampling
Default sampleRate is 1(100%). At low traffic that’s the right call — you want every sample. High traffic sites can lower it to stay within event quotas:
init("proj_xxx", {
extensions: {
webVitals: { sampleRate: 0.1 },
},
})The decision happens once per page load. If the page is sampled, all five metrics fire; if not, zero fire. You don’t get partial samples across metrics for the same visit.
Per-page analysis
The pathnameproperty makes segmentation trivial: ask “what’s the p75 LCP on /pricing” or “which pages have the worst INP”. Use the MCP tools to slice web_vital events by pathname and metric.
Gotchas
valueis a string. Cast to number if you aggregate client-side. This is a constraint of the property type system, not a bug.- One event per metric per page load — so a page that fires LCP, CLS, INP, FCP, and TTFB emits five events. Quota impact scales linearly with sampled pageviews.
- Metrics fire as they resolve. CLS and INP accumulate across the session and settle at pagehide, so they arrive later than LCP/FCP.
- If the peer dep isn’t installed, the extension silently does nothing. No console warnings outside debug mode.