How to measure Core Web Vitals in the field and in the lab
field data vs lab data, CrUX dataset, PageSpeed Insights, web-vitals.js, PerformanceObserver API, Lighthouse CI, synthetic monitoring
Measuring Core Web Vitals
Lab data (Lighthouse, DevTools) runs in a controlled environment โ single simulated user, fixed network throttling. Field data (CrUX, web-vitals.js) comes from real users across all their devices and connections. Both matter. Lab data finds issues; field data confirms fixes landed.
Field measurement with the web-vitals library (1KB gzipped):
import { onCLS, onINP, onLCP } from 'web-vitals';
function sendToAnalytics({ name, value, rating }) {
navigator.sendBeacon('/analytics', JSON.stringify({
metric: name,
value: Math.round(value),
rating // 'good' | 'needs-improvement' | 'poor'
}));
}
onCLS(sendToAnalytics);
onINP(sendToAnalytics);
onLCP(sendToAnalytics);Lab measurement โ run Lighthouse programmatically in CI to catch regressions before shipping:
# Install Lighthouse CI
npm install -g @lhci/cli
# Run against local server
lhci autorun --collect.url=http://localhost:3000PageSpeed Insights (pagespeed.web.dev) shows both: field data from the Chrome User Experience Report (CrUX) for the past 28 days, plus a fresh Lighthouse lab run. Check CrUX data first โ if the page doesn't have enough traffic, CrUX won't have field data, and you'll rely on lab only.
