Measuring & Monitoring

Performance & Core Web Vitals — Measuring & Monitoring
Performance & Core Web Vitals
Chapter 8 · Measuring & Monitoring

📊 Measuring & Monitoring

Chapter 1's tip box warned against chasing a Lighthouse score in isolation. This chapter covers exactly why lab and field data diverge, how to properly collect both, and how to keep a fast page from quietly regressing over time.

Lab Data: Deterministic, Not Representative

Lighthouse runs under fixed, simulated conditions — a specific network throttle profile, a specific CPU multiplier, a specific device emulation. This determinism is exactly its strength: it's the right tool for "did this specific change actually help, holding everything else constant?" It's also exactly its weakness — real users' actual conditions vary enormously and rarely match the simulated profile.

🌍 Field Data: Noisy, But Real

Real User Monitoring (RUM) collects actual measurements from real visitors' real browsers, devices, networks, and locations — inherently noisier than a controlled lab run, but it represents ground truth for what's actually being experienced.

CrUX (Chrome User Experience Report)

Google's public, aggregated field dataset from opted-in real Chrome users — available for free via PageSpeed Insights or the CrUX API, no instrumentation needed. Limited to sites with enough Chrome traffic, Chrome-only, and aggregated over a rolling 28-day window.

The web-vitals Library

Google's own small library for capturing Core Web Vitals directly in the browser, from your own actual visitors — real-time, not Chrome-only, not delayed by a rolling window, and specific to your real traffic mix rather than an aggregate.

Capturing Field Data Directly

import { onLCP, onINP, onCLS } from "web-vitals"; onLCP(sendToAnalytics); onINP(sendToAnalytics); onCLS(sendToAnalytics); function sendToAnalytics(metric) { navigator.sendBeacon("/analytics", JSON.stringify(metric)); }

Why You Need Both

Lab data lets you iterate quickly with reproducible conditions — real field data can't tell you within seconds whether a specific tweak helped. Field data tells you what's actually happening to real visitors, and confirms a lab-driven fix genuinely helped in the real world. Neither alone tells the full story — echoing exactly Chapter 1's original point.

Lab Alone vs Lab + Field

Lab Data Alone

Scores perfectly in Lighthouse — no visibility into what real 3G users or low-end devices actually experience.

Lab + Field

Fast iteration in the lab, confirmed by real measurements that the fix genuinely helped everyone, not just the simulated profile.

💰 Performance Budgets

Concrete numeric limits — "LCP must stay under 2.5s," "total JS under 300KB," "no single image over 200KB" — checked automatically, often in CI. Performance is a moving target, not a one-time fix: one new dependency here, one new tracking script there, and a fast page slowly becomes slow again without something acting as a guardrail.

// A simple CI budget check (conceptual) { "budgets": [ { "metric": "LCP", "max": "2.5s" }, { "metric": "total-js", "max": "300KB" } ] }

💻 Coding Challenges

Challenge 1: Wire Up the web-vitals Library

Write code using the web-vitals library that captures all three Core Web Vitals and logs each metric's name and value to the console instead of sending it anywhere.

Goal: Practice the basic setup for first-party field data collection.

→ Solution

Challenge 2: Diagnose Why Lab and Field Disagree

A page scores "Good" LCP in Lighthouse but CrUX field data shows "Needs Improvement" for real users. Using this chapter's material, explain one plausible cause and which data source you'd trust more for deciding whether the page is actually fast enough.

Goal: Practice applying the lab-vs-field distinction to a real disagreement, not just reciting the definitions.

→ Solution

Challenge 3: Design a Performance Budget

Propose three concrete performance budget rules for a content-heavy blog site (not an app), covering at least one Core Web Vital and at least one byte-weight limit, and briefly justify each threshold.

Goal: Practice setting concrete, enforceable numeric limits rather than vague goals.

→ Solution

⚠️ Gotcha: A Performance Budget With No Teeth

Setting a budget once and only reporting or logging violations, rather than actually failing a CI build when a limit is exceeded, means the budget will be silently ignored the first time a deadline pressures a team to ship "just this once" over budget. Every "just this once" compounds — the exact cumulative-regression problem the budget exists to prevent creeps back in through the same door, one small exception at a time. A budget only works as a guardrail if crossing it actually blocks the build; a budget that's merely advisory eventually gets treated as optional.

🎯 What's Next

Every technique from this course comes together in the final chapter: Capstone: Auditing and Fixing a Slow Page — walking a deliberately slow example page through LCP, CLS, and INP fixes, one issue at a time.