Frontend Labs
⋯

35. Core Web Vitals: LCP, INP, CLS — measuring and fixing them

Google's Core Web Vitals are the three metrics that most directly map to perceived user experience, and are used in Search ranking:

Metric Measures Good threshold Common fixes
LCP (Largest Contentful Paint) Time until the largest visible element (usually a hero image or heading) renders ≤ 2.5s Preload the LCP image, remove render-blocking CSS/JS, use SSR/SSG for above-the-fold content
INP (Interaction to Next Paint) Latency from a user interaction (click/tap/keypress) to the next painted frame reflecting it ≤ 200ms Break up long JS tasks (§37), avoid heavy synchronous work in event handlers, use requestIdleCallback for non-urgent work
CLS (Cumulative Layout Shift) Unexpected layout movement after initial render ≤ 0.1 Always set explicit width/height on images/embeds, reserve space for ads/late-loading content, avoid inserting content above existing content

Measuring them in real user sessions (not just synthetic lab tests) via the web-vitals library:

import { onLCP, onINP, onCLS } from "web-vitals";

onLCP((metric) => sendToAnalytics("LCP", metric.value));
onINP((metric) => sendToAnalytics("INP", metric.value));
onCLS((metric) => sendToAnalytics("CLS", metric.value));

Diagnosing a long task that hurts INP with the PerformanceObserver API directly (no library needed):

new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    if (entry.duration > 50) {   // "long task" threshold per the spec
      console.warn(`Long task: ${entry.duration.toFixed(1)}ms`, entry);
    }
  }
}).observe({ type: "longtask", buffered: true });

Generated from real-life-JS-guide.md · 8 Oct 2026 16:36