Beyond Code & Karma · Web Performance

Core Web Vitals

Five numbers Google uses to score the felt experience of your page — how fast it appears, how fast it answers, and how steady it stays. Explained through the Performance APIs that measure them, the one fix that moves each, and a live checker you can run right now.

Live in-browser tool · LCP · INP · CLS

A page can be fast on paper
and still feel broken.

Core Web Vitals are Google's attempt to measure the felt experience of a page, not just its byte count. Three are the headline vitals — LCP (how fast the main content appears), INP (how fast the page answers an interaction), and CLS (how much the layout jumps). Two more — TTFB and FCP — are diagnostic foundations that explain why the headline numbers land where they do. Google uses real-user field data on these for ranking, which is why a green badge is worth money.

The Secret: you can't fix what you don't measure honestly. Lab tools simulate; the only ground truth is the metric recorded on a real device, in a real session — exactly what the live checker on this page reads from your browser.
Loading — LCP
How quickly the largest thing in view renders. The visitor's first real sight of your content.
Responsiveness — INP
How fast the page answers a click, tap, or key. Replaced FID in March 2024 — it measures the whole latency.
Stability — CLS
How much content shifts under the user. Every jump that moves the button they were about to tap costs trust.
Foundations — TTFB & FCP
Server speed (TTFB) and first paint (FCP). Not headline vitals, but every slow LCP starts here.

A fast page is sevadharma toward the visitor

Hindu Philosophy Parallel

To serve a visitor's time and attention without making them wait, stumble, or lose their place is seva — selfless service — and dharma toward the one who came to you. The three headline vitals map cleanly onto three duties you owe every visitor.

LCP — Darshan
The first true sight you grant the user. A fast LCP is offering darshan without delay.
INP — Answering the Call
Responsiveness to the user's call — answering the touch without making them wait.
CLS — Sthirata
Steadiness. Never shifting the ground under the user's feet — the layout stays still.

And measuring your own vitals honestly — not flattering lab numbers, but the truth of a real session — is svadhyaya, self-study. You cannot serve what you refuse to see.

Each number, its threshold, its one fix

Thresholds below are the 2026 Google bands — Good, needs work, then Poor. For each metric there is one fix that moves the needle more than the rest.

LCP · Largest Contentful Paint
Time until the largest element in the viewport finishes rendering.
Good ≤ 2.5s · Poor > 4s
Fix: preload the hero image, serve it in a modern format, and kill render-blocking CSS/JS above the fold.
INP · Interaction to Next Paint
Worst-case latency from an interaction to the next painted frame.
Good ≤ 200ms · Poor > 500ms
Fix: break up long tasks and yield to the main thread so input handlers stay responsive.
CLS · Cumulative Layout Shift
Unitless score of how much visible content shifts unexpectedly.
Good ≤ 0.1 · Poor > 0.25
Fix: set explicit width/height on images and embeds, and reserve space for ads, banners, and late fonts.
TTFB · Time to First Byte
Time from navigation start until the first response byte arrives.
Good ≤ 800ms
Fix: cache at the edge / CDN and cut server work on the critical path.
FCP · First Contentful Paint
Time until the browser renders the first piece of DOM content.
Good ≤ 1.8s
Fix: inline critical CSS, drop render-blocking resources, and preconnect to required origins.
The headline three
LCP, INP, and CLS are the ranking vitals. TTFB and FCP are diagnostics — fix them to move LCP, not for their own scoreboard.

Measuring vitals with the native APIs

No library needed. The browser already exposes every vital through PerformanceObserver. Reading LCP is five lines:

observe-lcp.js
// Read this page's Largest Contentful Paint, live.
new PerformanceObserver((list) => {
  const entries = list.getEntries();
  const lcp = entries[entries.length - 1];  // last entry wins
  console.log('LCP', Math.round(lcp.startTime), 'ms');
}).observe({ type: 'largest-contentful-paint', buffered: true });
Why buffered: true: LCP candidates fire before your script runs. The buffered flag replays entries that already happened, so you never miss the real largest paint.

The CLS fix every site needs — reserve the box

The single biggest source of layout shift is media that loads with no reserved space. Give the browser the dimensions and the shift disappears:

cls-fix.html
// CLS killer: reserve the box BEFORE the image loads.
// The browser infers the ratio from width/height attrs…
<img src="hero.jpg" width="1200" height="630" alt="…" />

// …and one CSS rule keeps it fluid without ever shifting:
img { height: auto; }   // aspect-ratio inferred → zero layout shift

The page's lifecycle — where each vital lands

Load — TTFB

Navigation starts; the server responds. The first byte arrives. Everything downstream waits on this.

Paint — FCP → LCP

First pixels (FCP), then the largest element finishes rendering (LCP). The visitor now sees your content.

Interactive — INP

The user clicks or taps. INP records how long until the next frame paints the response. Long tasks hurt here.

Stable — CLS

Across the whole lifetime, every unexpected shift accumulates into CLS. A late font or image can spike it at any moment.

The cheat-sheet

MetricMeasuresGood / PoorTop fix
LCPLargest element render time≤ 2.5s / > 4sPreload hero, kill render-blockers
INPInteraction → next paint≤ 200ms / > 500msBreak long tasks, yield to main
CLSUnexpected layout movement≤ 0.1 / > 0.25Set width/height, reserve space
TTFBNavigation → first byte≤ 800ms / —Edge cache / CDN, cut server work
FCPFirst DOM content painted≤ 1.8s / —Inline critical CSS, preconnect

Your live vitals, right now

These two numbers are read from this page session by a real PerformanceObserver — not a simulation. Scroll and interact and watch them settle.

This page · live readout
● measuring…
LCP
Largest Contentful Paint · Good ≤ 2.5s
CLS
Cumulative Layout Shift · Good ≤ 0.1

The nuances that senior devs know

This is where the basic tutorials stop. Here's what actually decides your score at scale.

Lab tools like Lighthouse run on a simulated device and network — repeatable, great for debugging, but a fiction. Field data (the Chrome UX Report, or RUM) is the 75th-percentile of real users on real phones and flaky networks, and it's what Google ranks on. A green Lighthouse score with a red field score is common: your laptop is not your users.

First Input Delay only measured the delay before the first interaction's handler started — not how long the handler ran, and only once. Most pages passed FID trivially while still feeling sluggish. INP measures the full latency, from input to next paint, across all interactions, and reports the worst. It's a far harder and more honest bar.

CLS isn't just "things moved". Each shift score is impact fraction (how much of the viewport the unstable element covers) times distance fraction (how far it moved, relative to the viewport). Shifts are grouped into session windows and CLS is the worst window's sum. Shifts within 500ms of a user input are excluded — that's the hadRecentInput flag the live checker honours.

TTFB isn't a Core Web Vital, but a slow one caps every other metric — paint can't begin until bytes arrive. It's a chain: redirects, DNS, TLS, server think-time, then first byte. Edge caching and CDNs attack the network legs; cutting server work on the critical path attacks think-time. A 1s TTFB makes a green LCP nearly impossible.

Pro tip: the live checker reads TTFB from the navigation PerformanceEntry's responseStart — the same source DevTools uses.

Vitals are not vanity — they move real outcomes:

SurfaceWhy it matters
Google rankingCore Web Vitals are a confirmed ranking signal via the page experience system.
ConversionStudies repeatedly tie faster LCP and lower CLS to higher conversion and lower bounce.
Ad revenueLayout shift from late-loading ads both spikes CLS and triggers accidental clicks.
RetentionSluggish INP makes an app feel broken even when nothing is technically wrong.

The Karma of performance

The Karma Connection

Karma is the principle that every action has a consequence. Each performance choice you make is an action whose fruit the visitor eventually tastes — a preloaded hero, a yielded task, a reserved box. None of it is for show; it is service rendered before anyone arrives.

dharma.js
// Every paint is a darshan — the first true sight you grant.
showHeroFast();      // good LCP → seva, service to the visitor

// Every interaction deserves an answer without delay.
yieldToMain();       // low INP → responsiveness as dharma

// Never move the ground under their feet.
reserveSpace(img);   // width/height set → sthirata, steadiness

A fast LCP is darshan offered without delay. A low INP is answering the user's call the moment it comes. A stable layout is sthirata — never moving the ground beneath their feet. And measuring your own vitals honestly, refusing the comfort of flattering lab numbers, is svadhyaya: the self-study that makes the service real.

"Do the work well and do not cling to the score; serve the visitor's time, and the ranking follows." — the Gita, interpreted for performance engineers 🙏

Core Web Vitals Trivia

Three questions. No cheating. Your karma is watching.

Question 1
Which metric replaced First Input Delay (FID) as a Core Web Vital in March 2024?
Question 2
A good LCP score is which of these?
Question 3 — 🌶️ Spicy
Why might a page pass every metric in Lighthouse but still fail Core Web Vitals in Search Console?

The Six Truths of Core Web Vitals

LCP is Darshan
The largest paint is the visitor's first true sight of your content. Offer it without delay — preload, and clear the render path.
INP is Answering
Responsiveness is dharma. Break long tasks and yield to the main thread so every touch is answered before the next frame.
CLS is Sthirata
Steadiness. Reserve space for every image, ad, and font so the ground never shifts under the user's feet.
TTFB is the Tax
Not a headline vital, but it caps them all. Paint cannot begin until bytes arrive — cache at the edge.
Field Beats Lab
Lab data debugs; field data ranks. Trust the real-user 75th percentile over a flattering laptop run.
Svadhyaya — Measure Honestly
You cannot serve what you refuse to see. Read your own vitals from a real session, then fix what's red.

कर्म करो, फल की चिंता मत करो