Core Web Vitals: How to Measure and Improve Your SEO Performance

What Are Core Web Vitals (And Why Should You Care)?

Core Web Vitals are Google’s way of measuring how users actually experience your website. Not how fast your server responds or how optimized your code is — but how the page feels to someone trying to use it.

Since 2021, these metrics have been a confirmed ranking factor. But even if SEO wasn’t a concern, poor Core Web Vitals mean frustrated users, higher bounce rates, and lost conversions (see our guide on website metrics that matter).

The three metrics that matter:

Core Web Vitals thresholds showing good, needs improvement, and poor ranges for LCP, INP, and CLS
Core Web Vitals thresholds: what Google considers good, needs improvement, and poor

Let’s break down each one, how to measure them, and — most importantly — how to fix them.

LCP: Largest Contentful Paint

What It Measures

LCP measures when the largest visible element in the viewport finishes loading. This is usually:

  • A hero image
  • A large text block
  • A video poster image
  • A background image with text overlay

Google considers the largest element the “main content” because that’s what users are waiting to see.

What’s a Good Score?

Rating LCP Time What Users Experience
Good ≤ 2.5 seconds Page feels fast
Needs Improvement 2.5 – 4.0 seconds Noticeable delay
Poor > 4.0 seconds Users start leaving

Common LCP Problems and Fixes

Problem 1: Unoptimized images

The hero image is often the LCP element, and it’s often way too large.

<!-- Bad: 2MB hero image -->
<img src="hero-original.jpg" alt="Hero">

<!-- Good: Responsive, optimized images -->
<img 
  src="hero-800.webp" 
  srcset="hero-400.webp 400w, hero-800.webp 800w, hero-1200.webp 1200w"
  sizes="100vw"
  alt="Hero"
  loading="eager"
  fetchpriority="high"
>

Problem 2: Render-blocking resources

CSS and JavaScript in the <head> block rendering until they’re downloaded and parsed.

Fixes:

  • Inline critical CSS (above-the-fold styles)
  • Defer non-critical JavaScript: <script defer src="...">
  • Use rel="preload" for critical resources

Problem 3: Slow server response (TTFB)

If your server takes 2 seconds to respond, your LCP can’t be faster than 2 seconds.

Fixes:

  • Use a CDN for static assets
  • Enable server-side caching
  • Upgrade hosting if needed
  • Optimize database queries

INP: Interaction to Next Paint

What It Measures

INP replaced FID (First Input Delay) in March 2024. While FID only measured the first interaction, INP measures responsiveness throughout the entire page visit.

Every time a user clicks, taps, or presses a key, INP measures how long until the browser shows a visual response. The final INP score is typically the worst interaction (with some outliers excluded).

What’s a Good Score?

Rating INP Time What Users Experience
Good ≤ 200ms Instant response
Needs Improvement 200 – 500ms Slight lag
Poor > 500ms Feels broken

Common INP Problems and Fixes

Problem 1: Long JavaScript tasks

Any JavaScript task over 50ms blocks the main thread, making the page unresponsive.

// Bad: One massive function
function processAllData(data) {
  // 500ms of processing...
}

// Good: Break into smaller chunks
async function processDataInChunks(data) {
  for (const chunk of splitIntoChunks(data, 100)) {
    processChunk(chunk);
    await new Promise(r => setTimeout(r, 0)); // Yield to browser
  }
}

Problem 2: Too many event listeners

Each scroll, mousemove, or input event firing expensive handlers kills responsiveness.

Fixes:

  • Debounce or throttle event handlers
  • Use passive event listeners for scroll: { passive: true }
  • Remove listeners when not needed

Problem 3: Heavy third-party scripts

Chat widgets, analytics, ad scripts — they all compete for the main thread.

Fixes:

  • Audit third-party scripts — remove what you don’t need
  • Load non-critical scripts after page load
  • Use async or defer attributes
  • Consider web workers for heavy processing

CLS: Cumulative Layout Shift

What It Measures

CLS measures visual stability. Every time a visible element shifts position unexpectedly, it adds to your CLS score.

You’ve experienced bad CLS: you’re about to click a link, and an ad loads above it, pushing the link down. You click the ad instead. Frustrating.

What’s a Good Score?

Rating CLS Score What Users Experience
Good ≤ 0.1 Stable layout
Needs Improvement 0.1 – 0.25 Occasional shifts
Poor > 0.25 Content jumping everywhere

Common CLS Problems and Fixes

Problem 1: Images without dimensions

When an image loads without specified dimensions, the browser doesn’t know how much space to reserve.

<!-- Bad: No dimensions -->
<img src="photo.jpg" alt="Photo">

<!-- Good: Explicit dimensions -->
<img src="photo.jpg" alt="Photo" width="800" height="600">

<!-- Also good: CSS aspect ratio -->
<style>
.responsive-img {
  aspect-ratio: 4 / 3;
  width: 100%;
  height: auto;
}
</style>

Problem 2: Ads and embeds without reserved space

Ads load late and push content down.

<!-- Reserve space for ad -->
<div style="min-height: 250px;">
  <!-- Ad loads here -->
</div>

Problem 3: Web fonts causing text reflow

When a web font loads, text can resize and shift layout.

/* Prevent layout shift from fonts */
@font-face {
  font-family: 'CustomFont';
  src: url('font.woff2') format('woff2');
  font-display: swap; /* or 'optional' for less shift */
  size-adjust: 100.5%; /* Fine-tune to match fallback */
}

body {
  font-family: 'CustomFont', -apple-system, sans-serif;
}

Problem 4: Dynamic content injection

Adding content above existing content causes shifts. Always add below, or reserve space.

How to Measure Core Web Vitals

Lab Data vs. Field Data

There are two types of Core Web Vitals data:

Lab data — Simulated tests in controlled conditions (Lighthouse, PageSpeed Insights simulation). Good for debugging, but doesn’t reflect real user experience.

Field data — Real measurements from actual Chrome users (CrUX data). This is what Google uses for rankings. You need enough traffic (and Chrome users) to get field data.

Measurement Tools

For quick checks:

  • PageSpeed Insights — Shows both lab and field data
  • Chrome DevTools → Lighthouse tab
  • Chrome DevTools → Performance tab (for detailed debugging)

For ongoing monitoring:

  • Google Search Console → Core Web Vitals report (field data)
  • web-vitals JavaScript library — Track real user metrics
  • CrUX Dashboard — Historical field data trends

Tracking Core Web Vitals in Your Analytics

The best way to track Core Web Vitals is with Google’s web-vitals library:

<script type="module">
import {onLCP, onINP, onCLS} from 'https://unpkg.com/web-vitals@4?module';

function sendToAnalytics(metric) {
  // Send to your analytics platform
  const body = JSON.stringify({
    name: metric.name,
    value: metric.value,
    rating: metric.rating,
    delta: metric.delta,
    id: metric.id
  });
  
  // Use sendBeacon for reliability
  navigator.sendBeacon('/analytics', body);
}

onLCP(sendToAnalytics);
onINP(sendToAnalytics);
onCLS(sendToAnalytics);
</script>

For Google Analytics 4 (or alternatives), you can send as events:

function sendToGA4(metric) {
  gtag('event', metric.name, {
    value: Math.round(metric.name === 'CLS' ? metric.value * 1000 : metric.value),
    metric_id: metric.id,
    metric_value: metric.value,
    metric_rating: metric.rating
  });
}

Prioritizing Fixes: Where to Start

When all three metrics need work, here’s how to prioritize:

1. Fix CLS First

CLS fixes are usually the easiest and have immediate impact. Adding image dimensions or reserving ad space takes minutes.

2. Tackle LCP Second

LCP improvements often require:

  • Image optimization (1-2 hours)
  • Server improvements (varies)
  • Critical CSS extraction (2-4 hours)

3. Address INP Last

INP problems usually require JavaScript refactoring, which takes longer and carries more risk. Start with quick wins like deferring third-party scripts.

Common Mistakes to Avoid

Mistake 1: Only testing on fast connections

Your fiber connection isn’t representative. Test with throttling:

  • Chrome DevTools → Network tab → Throttle to “Slow 3G”
  • Performance tab → CPU throttle to 4x slowdown

Mistake 2: Ignoring mobile

Google uses mobile Core Web Vitals for ranking. Mobile devices have slower CPUs and networks — problems are amplified.

Mistake 3: Optimizing for lab scores only

Your Lighthouse score can be 100 while real users have a poor experience. Always validate with field data.

Mistake 4: Breaking functionality for speed

Don’t remove essential features just to hit arbitrary numbers. A fast but unusable site is worse than a slightly slower functional one.

Quick Wins Checklist

Start here for immediate improvements:

LCP Quick Wins:

  • ☐ Compress and resize hero images
  • ☐ Convert images to WebP format
  • ☐ Add fetchpriority="high" to LCP image
  • ☐ Preload critical fonts
  • ☐ Enable browser caching

INP Quick Wins:

  • ☐ Defer non-critical JavaScript
  • ☐ Remove unused third-party scripts
  • ☐ Add loading="lazy" to below-fold images
  • ☐ Use passive: true for scroll listeners

CLS Quick Wins:

  • ☐ Add width/height to all images
  • ☐ Reserve space for ads and embeds
  • ☐ Use font-display: swap
  • ☐ Avoid inserting content above existing content

The Bottom Line

Core Web Vitals aren’t just another SEO checkbox. They measure real user experience — and Google rewards sites that prioritize their users.

Start by measuring where you actually stand (field data, not just lab tests). Fix CLS first for quick wins. Then systematically work through LCP and INP.

Remember: the goal isn’t a perfect Lighthouse score. It’s a site that loads fast, responds instantly, and doesn’t frustrate users. The rankings will follow.

Alicia Bennett

Lead web analyst with 12+ years of experience helping businesses make sense of their data. I write about privacy-first analytics, open-source tools, and practical implementation — the stuff that actually moves the needle.

Leave a Reply