Core Web Vitals Optimization: LCP, INP, CLS Complete Guide (2025)
Master Core Web Vitals optimization for 2025. Complete guide to improving LCP, INP, and CLS for better SEO rankings, user experience, and conversions with actionable techniques.
Master Core Web Vitals optimization for 2025. Complete guide to improving LCP, INP, and CLS for better SEO rankings, user experience, and conversions with actionable techniques.
Your website's Core Web Vitals scores directly impact your Google search rankings, conversion rates, and revenue. In March 2024, Google made a critical change--nearly 600,000 websites that previously passed suddenly failed when Interaction to Next Paint (INP) replaced First Input Delay (FID). If you haven't optimized for the 2025 Core Web Vitals metrics, you're losing traffic and money to competitors who have. This guide shows you exactly how to optimize LCP, INP, and CLS to pass Google's thresholds and keep your rankings.
What Are Core Web Vitals?
Core Web Vitals are Google's official metrics for measuring real-world user experience on your website. They became a ranking factor in June 2021 and directly affect your search positions.
The Three Core Web Vitals for 2025
| Metric | What It Measures | Good Score | Impact |
|---|---|---|---|
| LCP (Largest Contentful Paint) |
How fast your main content loads | Under 2.5 seconds | Loading performance |
| INP (Interaction to Next Paint) |
How quickly page responds to user interactions | Under 200 milliseconds | Interactivity & responsiveness |
| CLS (Cumulative Layout Shift) |
Visual stability during page load | Under 0.1 | Visual stability |
March 2024 Major Change: INP Replaced FID
Google officially replaced First Input Delay (FID) with Interaction to Next Paint (INP) in March 2024. INP is a stricter metric that measures responsiveness throughout the entire page lifecycle, not just the first interaction. 600,000 websites went from passing to failing when this change took effect.
If you haven't optimized for INP yet, you're likely failing this metric and losing rankings.
Why Core Web Vitals Matter in 2025
- Direct ranking factor - Google uses these scores to determine search positions (especially mobile-first indexing)
- Revenue impact - The Economic Times improved CLS by 250% and reduced bounce rates by 43%
- Conversion rates - Every 0.1 second delay in mobile page load decreases conversion rates by 8.4%
- User satisfaction - 53% of mobile users abandon sites that take longer than 3 seconds to load
- Mobile-first indexing - Google ranks based on your mobile scores, not desktop
- Competitive advantage - Sites with better Core Web Vitals outrank slower competitors with similar content
LCP Optimization: Largest Contentful Paint
LCP measures how long it takes for the largest visible element (hero image, heading, video) to appear on screen. Good LCP is under 2.5 seconds; poor LCP is over 4 seconds.
What Counts as LCP Element?
The browser considers these elements for LCP:
<img>elements<image>elements inside<svg><video>elements with poster images- Elements with background images loaded via CSS
url() - Block-level elements containing text nodes or inline text elements
Common LCP Problems and Fixes
Problem 1: Slow Server Response Time
Symptom: Time to First Byte (TTFB) over 600ms
Solutions:
- Upgrade hosting: Move from shared hosting to VPS or managed WordPress hosting (WP Engine, Kinsta, Cloudways)
- Use CDN: Cloudflare, CloudFront, or platform-specific CDNs distribute content closer to users
- Enable caching: Browser caching, server-side caching (Redis, Varnish)
- Optimize database: Clean up revisions, optimize tables, add indexes
- Reduce redirects: Each redirect adds 200-600ms delay
Problem 2: Render-Blocking Resources
Symptom: CSS and JavaScript files blocking page render
Solutions:
- Inline critical CSS: Extract above-the-fold CSS and inline it in
<head> - Defer non-critical CSS: Load below-the-fold styles asynchronously
- Defer JavaScript: Add
deferorasyncattributes to non-critical scripts - Minimize CSS/JS: Use minification and compression (Gzip, Brotli)
- Remove unused code: Audit with Coverage tool in Chrome DevTools
Example: Defer Non-Critical CSS
<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="styles.css"></noscript>
Problem 3: Large LCP Element (Hero Image)
Symptom: Hero image is 2-5 MB and takes 3+ seconds to load
Solutions:
- Optimize image size: Compress to 80-90% quality, target under 200KB for hero images
- Use modern formats: WebP reduces size by 25-35%, AVIF by 50% vs JPEG
- Responsive images: Serve different sizes with
srcsetandsizes - Preload LCP image: Tell browser to prioritize loading
- Use CDN: Serve images from geographically distributed servers
- Proper dimensions: Set width and height attributes to prevent layout shifts
Example: Preload Hero Image
<link rel="preload" as="image" href="hero.webp"
imagesrcset="hero-mobile.webp 640w, hero-tablet.webp 1024w, hero.webp 1920w"
imagesizes="100vw">
Example: Responsive Images
<img src="hero-1920.webp"
srcset="hero-640.webp 640w, hero-1024.webp 1024w, hero-1920.webp 1920w"
sizes="100vw"
alt="Hero image"
width="1920"
height="1080">
Problem 4: Web Fonts Blocking Render
Symptom: Text not appearing until custom fonts load (FOIT - Flash of Invisible Text)
Solutions:
- Preload fonts: Priority load for critical fonts
- Font-display: swap: Show fallback font immediately, swap when custom font loads
- Subset fonts: Include only characters you actually use (reduces file size 60-80%)
- Self-host fonts: Avoid third-party requests to Google Fonts (save 200-400ms)
- Use system fonts: Consider using system font stack for body text
Example: Preload and Optimize Fonts
<link rel="preload" href="/fonts/roboto-subset.woff2" as="font" type="font/woff2" crossorigin>
<style>
@font-face {
font-family: 'Roboto';
src: url('/fonts/roboto-subset.woff2') format('woff2');
font-display: swap;
unicode-range: U+0020-007F; /* Latin subset only */
}
</style>
LCP Quick Wins Checklist
- ✅ Optimize hero image (compress to <200KB, use WebP/AVIF)
- ✅ Preload LCP element with
<link rel="preload"> - ✅ Use CDN for images and static assets
- ✅ Inline critical CSS (above-the-fold styles)
- ✅ Defer non-critical JavaScript
- ✅ Optimize server response time (TTFB under 600ms)
- ✅ Enable text compression (Gzip or Brotli)
- ✅ Remove render-blocking resources
- ✅ Set explicit width/height on images
- ✅ Use
font-display: swapfor web fonts
INP Optimization: Interaction to Next Paint
INP measures how quickly your page responds to user interactions (clicks, taps, keyboard input). Good INP is under 200ms; poor INP is over 500ms. INP replaced FID in March 2024 and is more demanding.
Why INP Is Harder Than FID
- FID measured first interaction only - INP measures ALL interactions throughout page lifecycle
- FID accepted 100ms - INP requires under 200ms (stricter)
- FID ignored subsequent sluggishness - INP catches all responsiveness issues
- More comprehensive - Scroll, hover, continuous interactions all count
Common INP Problems and Fixes
Problem 1: Long JavaScript Tasks
Symptom: Main thread blocked by JavaScript execution over 50ms
Solutions:
- Break up long tasks: Split tasks over 50ms into smaller chunks with
setTimeout()orrequestIdleCallback() - Code splitting: Load JavaScript on-demand instead of one massive bundle
- Remove unnecessary JavaScript: Audit third-party scripts (analytics, ads, chat widgets)
- Web Workers: Move heavy computation off main thread
- Lazy load non-critical scripts: Defer loading until actually needed
Example: Break Long Task
// Bad: Blocks main thread
for (let i = 0; i < 10000; i++) {
processItem(items[i]);
}
// Good: Yields to browser between chunks
async function processItemsAsync() {
for (let i = 0; i < items.length; i++) {
processItem(items[i]);
// Yield every 50 items
if (i % 50 === 0) {
await new Promise(resolve => setTimeout(resolve, 0));
}
}
}
Problem 2: Heavy Event Handlers
Symptom: Click or scroll events trigger expensive operations
Solutions:
- Debounce/Throttle: Limit how often event handlers fire
- Passive event listeners: Mark scroll/touch events as passive
- Request Animation Frame: Schedule visual updates efficiently
- Event delegation: Use single handler on parent instead of many on children
- Optimize DOM manipulation: Batch updates, use DocumentFragment
Example: Debounce Scroll Handler
// Debounce utility
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
};
}
// Use debounced handler
window.addEventListener('scroll', debounce(() => {
// Expensive scroll logic here
updateParallax();
}, 100));
Example: Passive Event Listener
// Improves scroll performance
window.addEventListener('scroll', handleScroll, { passive: true });
window.addEventListener('touchstart', handleTouch, { passive: true });
Problem 3: Large DOM Size
Symptom: DOM tree has 1,500+ nodes, slowing down rendering and interaction
Solutions:
- Limit DOM depth: Avoid deeply nested elements (target max 32 levels)
- Virtual scrolling: Render only visible items in long lists
- Remove hidden elements: Actually remove from DOM, don't just hide with CSS
- Lazy render sections: Render below-fold content after initial load
- Simplify HTML structure: Remove unnecessary wrapper divs
Target DOM Metrics:
- Total nodes: Under 1,500
- DOM depth: Under 32 levels
- Parent nodes with children: Under 60
Problem 4: Third-Party Scripts Blocking Interaction
Symptom: Analytics, ads, chat widgets delay page responsiveness
Solutions:
- Load asynchronously: Use
asyncordeferon script tags - Delay non-critical scripts: Load after page interactive
- Self-host when possible: Avoid network requests to third parties
- Use facades: Lazy load YouTube embeds, social widgets
- Remove unnecessary scripts: Audit what you actually need
- Monitor impact: Use Request Blocking in DevTools to test performance without each script
Example: Delay Third-Party Scripts
// Load analytics after page interactive
window.addEventListener('load', () => {
setTimeout(() => {
// Load Google Analytics
const script = document.createElement('script');
script.src = 'https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID';
script.async = true;
document.head.appendChild(script);
}, 3000); // 3 second delay
});
INP Quick Wins Checklist
- ✅ Break JavaScript tasks longer than 50ms into chunks
- ✅ Defer non-critical third-party scripts
- ✅ Debounce/throttle scroll and resize handlers
- ✅ Use passive event listeners for scroll/touch
- ✅ Reduce DOM size (under 1,500 nodes)
- ✅ Code-split large JavaScript bundles
- ✅ Remove unused JavaScript (tree shaking)
- ✅ Optimize event handlers (delegation, minimal logic)
- ✅ Use Web Workers for heavy computation
- ✅ Lazy load below-the-fold JavaScript
CLS Optimization: Cumulative Layout Shift
CLS measures visual stability--how much content unexpectedly moves during page load. Good CLS is under 0.1; poor CLS is over 0.25. Every unexpected layout shift frustrates users and harms conversions.
What Causes Layout Shifts?
- Images without dimensions
- Ads, embeds, iframes without reserved space
- Web fonts causing FOIT/FOUT (Flash of Invisible/Unstyled Text)
- Dynamically injected content above existing content
- Actions that trigger network requests before page fully loaded
Common CLS Problems and Fixes
Problem 1: Images Without Dimensions
Symptom: Content jumps down when images load
Solution: Always set width and height attributes on <img> tags
Bad (causes CLS):
<img src="hero.jpg" alt="Hero">
Good (prevents CLS):
<img src="hero.jpg" alt="Hero" width="1920" height="1080">
Modern browsers automatically calculate aspect ratio from width/height and reserve space, even with CSS making images responsive.
CSS for Responsive Images:
img {
max-width: 100%;
height: auto;
}
Problem 2: Ads and Embeds Causing Shifts
Symptom: Content jumps when ads or YouTube embeds load
Solutions:
- Reserve space with min-height: Set minimum dimensions for ad slots
- Use aspect-ratio boxes: CSS aspect-ratio or padding-bottom trick
- Placeholder elements: Show skeleton screens while loading
- Avoid inserting content above fold: New content should appear below existing
Example: Reserve Space for Ad
<div class="ad-container" style="min-height: 250px;">
<!-- Ad loads here -->
</div>
Example: YouTube Embed with Aspect Ratio
<div style="aspect-ratio: 16 / 9;">
<iframe src="https://youtube.com/embed/..."
width="100%" height="100%"></iframe>
</div>
Problem 3: Web Fonts Causing Layout Shift
Symptom: Text reflows when custom font loads, changing line breaks and layout
Solutions:
- font-display: optional: Only use custom font if it loads quickly, otherwise stick with fallback
- Match fallback font metrics: Adjust fallback font size to match custom font
- Preload critical fonts: Ensure fonts load before text renders
- Font subsetting: Smaller file = faster load = less shift
Example: Match Fallback Font Size
@font-face {
font-family: 'CustomFont';
src: url('custom.woff2') format('woff2');
font-display: optional;
}
body {
font-family: 'CustomFont', Arial, sans-serif;
/* Adjust to match CustomFont metrics */
font-size: 16px;
line-height: 1.5;
}
CSS Font Loading API:
// Ensure font loaded before showing text
document.fonts.load('16px CustomFont').then(() => {
document.body.classList.add('fonts-loaded');
});
Problem 4: Dynamic Content Injection
Symptom: Banners, notifications, cookie consent shifting content down
Solutions:
- Use overlays: Position absolutely or fixed instead of pushing content
- Reserve space on page load: Even if content loads later
- Insert at bottom: Append new content below visible area
- Animate with transform: Use CSS transform instead of changing dimensions
Example: Fixed Position Banner (No CLS)
.cookie-banner {
position: fixed;
bottom: 0;
left: 0;
right: 0;
/* Doesn't push content - overlays instead */
}
CLS Quick Wins Checklist
- ✅ Set width and height on ALL images
- ✅ Reserve space for ads and embeds (min-height or aspect-ratio)
- ✅ Use font-display: optional or font-display: swap
- ✅ Preload critical fonts
- ✅ Avoid injecting content above existing content
- ✅ Use overlays/fixed position for banners
- ✅ Set dimensions on video embeds
- ✅ Avoid animations that change dimensions (use transform)
- ✅ Load below-fold images with lazy loading
- ✅ Reserve skeleton space for dynamic content
Testing and Measuring Core Web Vitals
Essential Testing Tools
1. PageSpeed Insights (Free, Official Google Tool)
URL: https://pagespeed.web.dev/
What it does:
- Tests both mobile and desktop
- Shows field data (real users) and lab data (simulated)
- Provides specific recommendations
- Shows if you're passing Core Web Vitals thresholds
How to use:
- Enter your URL
- Click "Analyze"
- Check "Core Web Vitals Assessment" (pass/fail)
- Review "Opportunities" and "Diagnostics" sections
- Fix issues, retest until passing
2. Chrome DevTools (Built-in Browser Tool)
Best for: Detailed debugging and real-time testing
Key Features:
- Performance tab: Record page load, identify bottlenecks
- Lighthouse: Run audits directly in browser
- Coverage: Find unused CSS/JavaScript
- Network tab: See resource load times and sizes
- Rendering tab: Paint flashing, layout shift regions
How to test CLS in DevTools:
- Open DevTools (F12)
- Click three dots → More tools → Rendering
- Enable "Layout Shift Regions"
- Reload page and see blue highlights where shifts occur
3. Google Search Console (Real User Data)
Best for: See how real users experience your site
What it shows:
- Core Web Vitals report for your entire site
- Mobile vs Desktop performance
- URLs grouped by issue type
- Historical trends (how you're improving)
How to use:
- Open Google Search Console
- Navigate to Core Web Vitals report
- Review "Poor URLs" that fail thresholds
- Click groups to see specific failing pages
- Fix issues, wait 28 days for new data
4. Web Vitals Chrome Extension
Install: Chrome Web Store → "Web Vitals"
What it does:
- Shows LCP, INP, CLS in real-time as you browse
- HUD overlay on every page
- Instant feedback while developing
Mobile vs Desktop Testing
Critical: Google Uses Mobile Scores for Rankings
Google's mobile-first indexing means your mobile Core Web Vitals determine your search rankings, not desktop. Many sites pass on desktop but fail on mobile.
Always test:
- Real mobile devices (not just DevTools mobile emulation)
- Slow 3G/4G connections (not just WiFi)
- Various phone models (flagship and budget Android)
Platform-Specific Optimization
WordPress Core Web Vitals Optimization
Essential Plugins:
- WP Rocket: Comprehensive caching, minification, lazy loading, CDN integration
- Imagify or ShortPixel: Automatic image compression and WebP conversion
- Perfmatters: Disable unnecessary features, defer JavaScript, optimize database
- Asset CleanUp: Disable CSS/JS on pages that don't need them
Quick WordPress Fixes:
- Upgrade hosting: Shared hosting won't cut it (use managed WP hosting)
- Use lightweight theme: GeneratePress, Astra, Kadence
- Limit plugins: Deactivate and delete unused plugins
- Optimize database: WP-Optimize plugin
- Enable lazy loading: Built-in since WP 5.5, or use WP Rocket
- Use object caching: Redis or Memcached
- Defer JavaScript: WP Rocket or Autoptimize
Shopify Core Web Vitals Optimization
Shopify-Specific Challenges:
- Limited control over server-side code
- Heavy theme JavaScript for product pages
- Third-party app scripts
Shopify Optimization Strategies:
- Choose fast theme: Dawn (default), Sense, Studio (designed for speed)
- Remove unused apps: Each app adds scripts; audit regularly
- Optimize images: Shopify CDN handles basic optimization, but compress before upload
- Use native lazy loading: Shopify 2.0 themes support this
- Defer third-party scripts: Load after page interactive
- Minimize sections: Shopify sections add HTML/CSS; keep homepage lean
- Use Cloudflare: Add CDN layer on top of Shopify
React/Next.js Core Web Vitals Optimization
Next.js Advantages:
- Built-in image optimization with next/image
- Automatic code splitting
- Server-side rendering (SSR) for faster LCP
- Font optimization
Next.js Best Practices:
- Use next/image: Automatic optimization, lazy loading, modern formats
- Enable Static Generation (SSG): Pre-render pages at build time
- Dynamic imports: Load components on-demand
- Optimize fonts: Use next/font for automatic font optimization
- Monitor bundle size: Use @next/bundle-analyzer
Example: Next.js Image Optimization
import Image from 'next/image'
export default function Hero() {
return (
<Image
src="/hero.jpg"
alt="Hero image"
width={1920}
height={1080}
priority // Preload LCP image
placeholder="blur" // Blur-up placeholder
/>
)
}
Real-World Case Studies
Case Study 1: The Economic Times (News Site)
Results:
- CLS improved by 250% (from 0.25 to 0.09)
- LCP improved by 80% (to 2.5 seconds)
- Bounce rate reduced by 43%
What they did:
- Set explicit dimensions on all images and ads
- Optimized font loading with font-display: swap
- Preloaded hero images
- Reserved space for dynamic ad units
- Implemented lazy loading for below-fold content
Case Study 2: E-commerce Site (Anonymous)
Starting Point:
- LCP: 4.2 seconds (poor)
- INP: 380ms (poor)
- CLS: 0.18 (needs improvement)
After Optimization:
- LCP: 2.1 seconds (good) - 50% improvement
- INP: 180ms (good) - 53% improvement
- CLS: 0.05 (good) - 72% improvement
Business Impact:
- Conversion rate increased 11%
- Organic traffic up 23% (better rankings)
- Mobile revenue up 31%
Key optimizations:
- Migrated to faster hosting (Cloudways)
- Converted all product images to WebP
- Implemented CDN (Cloudflare)
- Deferred third-party scripts (Facebook Pixel, Google Ads)
- Reduced JavaScript bundle size by 60%
Quick Reference: Core Web Vitals Thresholds
| Metric | Good | Needs Improvement | Poor |
|---|---|---|---|
| LCP | ≤ 2.5s | 2.5s - 4.0s | > 4.0s |
| INP | ≤ 200ms | 200ms - 500ms | > 500ms |
| CLS | ≤ 0.1 | 0.1 - 0.25 | > 0.25 |
Passing Threshold
To pass Core Web Vitals assessment, 75% of page views must meet the "Good" threshold for all three metrics. This is measured at the 75th percentile of field data (real users).
Wrapping Up: Your Core Web Vitals Action Plan
Core Web Vitals directly impact your revenue, rankings, and user satisfaction. Here's your step-by-step action plan:
30-Day Optimization Plan
Week 1: Measure and Prioritize
- Test all key pages in PageSpeed Insights
- Check Search Console Core Web Vitals report
- Identify failing pages and common issues
- Prioritize high-traffic pages first
Week 2: LCP Optimization
- Optimize hero images (compress, use WebP, preload)
- Enable CDN for images and static assets
- Inline critical CSS
- Defer non-critical JavaScript
- Optimize server response time (upgrade hosting if needed)
Week 3: INP and CLS Optimization
- Set width/height on all images
- Reserve space for ads and embeds
- Optimize font loading (preload, font-display: swap)
- Break up long JavaScript tasks
- Defer third-party scripts
- Reduce DOM size
Week 4: Test, Refine, Monitor
- Retest all pages in PageSpeed Insights
- Test on real mobile devices
- Fix any remaining issues
- Set up ongoing monitoring
- Wait 28 days for Search Console to reflect changes
Key Takeaways
- Mobile scores matter most - Google ranks based on mobile performance
- INP is the new challenge - More demanding than FID; focus on JavaScript optimization
- Images are usually the culprit - Optimize, compress, set dimensions, use modern formats
- Real user data beats lab data - Monitor Search Console for real-world performance
- Small improvements = big impact - Every 0.1s improvement in LCP can boost conversions
- Test continuously - Performance degrades over time; monitor and maintain
Additional Resources
- Official Google Documentation: web.dev/vitals/
- PageSpeed Insights: pagespeed.web.dev
- Google Search Console: Monitor real user Core Web Vitals
- Web Vitals Chrome Extension: Real-time monitoring while browsing
Ready to optimize?
Use Convert a Document to shrink files without sacrificing quality.