Skip to content
Novandri.

Core Web Vitals: Diagnose LCP, INP, and CLS

A developer's guide to Core Web Vitals: diagnose LCP, INP, and CLS, understand CrUX field data vs Lighthouse lab scores, and fix real user performance bottlenecks.

Rachmadwipa Novandri7 min read

For years, measuring web performance meant tracking generic metrics like "Page Load Time" or "DOMContentLoaded." These legacy metrics failed to capture the actual user experience: a page could trigger window.onload while remaining a blank white screen, or load visibly while freezing the browser interface whenever a user attempted to click a button.

To bridge the gap between technical network events and real human perception, Google introduced Core Web Vitals (CWV).

Direct Answer: Core Web Vitals are three standardized user-centric metrics: Largest Contentful Paint (LCP) measures loading velocity (target: ≤ 2.5s), Interaction to Next Paint (INP) measures interaction responsiveness (target: ≤ 200ms), and Cumulative Layout Shift (CLS) measures visual stability (target: ≤ 0.1). Google evaluates compliance at the 75th percentile of real users over a rolling 28-day window via the Chrome User Experience Report (CrUX). While CWV serves as an official Google page experience ranking signal, its primary function is operational: fixing LCP, INP, and CLS eliminates real user friction and bounce rates.

Understanding the architectural root causes of these three metrics allows developers to diagnose and fix performance regressions systematically.

Core Web Vitals Trio (75th Percentile of Real Users)
  ├── 1. Loading Performance: LCP (Largest Contentful Paint) ──► Target: ≤ 2.5s
  │     └── When does the main above-the-fold content become visible?
  │
  ├── 2. Responsiveness: INP (Interaction to Next Paint)     ──► Target: ≤ 200ms
  │     └── How quickly does the UI provide visual feedback after user input?
  │
  └── 3. Visual Stability: CLS (Cumulative Layout Shift)     ──► Target: ≤ 0.1
        └── Does content jump unexpectedly while the document loads?

1. Core Web Vitals Defined: LCP, INP, and CLS

Google evaluates pages against three specific thresholds:

MetricMeasures"Good" Threshold"Needs Improvement""Poor" Threshold
LCPPerceived Loading Speed≤ 2.5 seconds2.5s - 4.0s> 4.0 seconds
INPInteraction Latency≤ 200 milliseconds200ms - 500ms> 500 milliseconds
CLSVisual Stability≤ 0.10.1 - 0.25> 0.25

Why INP Replaced FID

In March 2024, Google formally replaced First Input Delay (FID) with Interaction to Next Paint (INP).

  • FID (Legacy): Measured only the initial input delay of the very first user interaction, ignoring the time taken to run event callbacks or update the screen.
  • INP (Current Standard): Evaluates all user interactions (clicks, taps, keystrokes) across the entire session lifecycle, reporting the latency of the worst interaction. This makes INP a far more rigorous measure of UI responsiveness.

2. Lab Data vs Field Data (CrUX): Why Lighthouse Lies

A frequent point of frustration for engineering teams is achieving a 100/100 score in Google Lighthouse, only to fail Core Web Vitals in Google Search Console:

Lighthouse (Lab Data)                      vs   Chrome User Experience Report (Field Data)
────────────────────────────────────────────────┼─────────────────────────────────────────────
• Synthetic single run on a high-spec Mac       • Aggregated telemetry from millions of Chrome users
• Simulated throttling (packet delay simulation)• Real cellular networks (3G, 4G, congested 5G)
• No real human interactions (cannot test INP)  • Real user taps, clicks, and page scrolling
• Snapshot in time                              • Rolling 28-day 75th percentile average

Search Engine Rule: Google Search does not rank pages based on Lighthouse lab scores. Google's ranking algorithms evaluate Field Data extracted from the Chrome User Experience Report (CrUX). If your 75th percentile mobile users on budget smartphones experience slow LCP or sluggish INP, your page fails Core Web Vitals regardless of your local lab score.


3. Diagnosing Largest Contentful Paint (LCP)

LCP measures the time required to render the largest visible element in the viewport—typically a hero image, video poster, or large heading block.

To diagnose a slow LCP, decompose it into its Four Sub-Phases:

Total LCP = TTFB + Resource Load Delay + Resource Load Duration + Element Render Delay
[Request Start]
       │
       ├─► 1. TTFB (Time to First Byte): Waiting for initial HTML stream (~20% of LCP)
       │
       ├─► 2. Resource Load Delay: Time before browser discovers the hero image (~10%)
       │
       ├─► 3. Resource Load Duration: Time spent downloading image bytes (~40%)
       │
       └─► 4. Element Render Delay: Time spent waiting for JS/CSS before painting (~30%)

High-Impact LCP Fixes:

  1. Eliminate Resource Load Delay with fetchpriority="high": By default, browsers treat images as low-priority resources. For hero images, tell the preload scanner to fetch the asset immediately:
    <img src="/hero.webp" fetchpriority="high" alt="Hero banner" />
    
  2. Never Lazy-Load the LCP Element: Adding loading="lazy" to your above-the-fold hero image prevents the browser from downloading the image until layout calculations finish, artificially inflating LCP by seconds.
  3. Preload Critical Images: If the LCP element is loaded via CSS (background-image), it is hidden from the HTML preload scanner. Declare it explicitly in the <head>:
    <link rel="preload" fetchpriority="high" as="image" href="/hero.webp" type="image/webp" />
    

4. Diagnosing Interaction to Next Paint (INP)

INP measures the duration from when a user interacts with the page (e.g., clicking a navigation accordion or adding an item to a cart) until the browser presents the next visual frame confirming the action.

Every interaction comprises three phases:

Total INP = Input Delay + Processing Duration + Presentation Delay
[User Clicks Button]
         │
         ▼ (1. Input Delay: Waiting for main thread to finish background tasks)
[Event Listener Executes]
         │
         ▼ (2. Processing Duration: Time spent running JavaScript callbacks)
[DOM Updates & Style Recalculations]
         │
         ▼ (3. Presentation Delay: Browser composites and paints pixels to screen)
[Next Frame Rendered]

High-Impact INP Fixes:

  1. Break Up Long Tasks (> 50ms): If a script runs continuously on the main thread for more than 50ms, the browser cannot process user clicks during that window. Yield execution back to the main thread using scheduler.yield() or setTimeout:
    async function handleHeavyFilter() {
      // Run first calculation
      filterDatasetPartOne();
      
      // Yield control to let browser paint or handle input
      if ('scheduler' in window && 'yield' in scheduler) {
        await scheduler.yield();
      } else {
        await new Promise(resolve => setTimeout(resolve, 0));
      }
      
      // Run second calculation
      filterDatasetPartTwo();
    }
    
  2. Avoid Heavy Re-rendering in Event Handlers: Debounce expensive search filtering inputs and avoid synchronous DOM mutations that force layout thrashing.

5. Diagnosing Cumulative Layout Shift (CLS)

CLS measures visual instability: when visible elements change their starting position from one rendered frame to the next without user interaction.

Layout Shift Score = Impact Fraction * Distance Fraction
Frame 1: User starts reading paragraph text
Frame 2: Un-sized banner ad loads above paragraph ──► Pushes paragraph down by 300px!
Result:  User loses reading place or accidentally clicks the wrong link (High CLS)

High-Impact CLS Fixes:

  1. Always Set Explicit width and height on Media: Setting explicit dimensions (or CSS aspect-ratio) allows the browser to allocate the correct layout box before the image or video payload downloads:
    <img src="/article-cover.jpg" width="1200" height="630" style="aspect-ratio: 1200 / 630; width: 100%; height: auto;" />
    
  2. Reserve Space for Dynamic Ad Slots and Embeds: If your application injects third-party advertisements or cookie consent banners, reserve a placeholder container with fixed minimum heights (min-height: 250px) so content below does not shift when the ad renders.
  3. Prevent Font Swapping Shifts (FOUT): When custom web fonts load, they can render with different line heights than the system fallback font. Use font-display: optional or modern CSS @font-face overrides (size-adjust, ascent-override) to match fallback dimensions perfectly.

6. The Core Web Vitals Remediation Matrix

MetricTargetDominant Root CausesHigh-Impact Architectural Remedy
LCP≤ 2.5sSlow TTFB; hidden hero images; loading="lazy" on hero.Preload hero image; apply fetchpriority="high"; optimize edge caching.
INP≤ 200msLong JavaScript tasks (> 50ms); heavy hydration callbacks.Break tasks with scheduler.yield(); reduce third-party script overhead.
CLS≤ 0.1Unsized images/video; dynamic ads injected without reserved containers; font shifts.Define explicit aspect-ratio; reserve ad containers; use font-display: optional.

Summary & Next Steps

Core Web Vitals represent a fundamental shift in search engineering: moving from static document evaluation to live, user-perceived runtime quality. While high scores alone will not rescue irrelevant content, passing the 75th percentile CrUX threshold ensures your infrastructure meets Google's page experience baseline while eliminating user bounce rates.

Continue exploring infrastructure and performance diagnostics: