How to Improve Core Web Vitals
How to Improve Core Web Vitals
Quick answer: Core Web Vitals are Google’s page speed metrics (LCP, CLS, INP). Fix them by compressing images (LCP), adding image dimensions (CLS), and reducing JavaScript (INP). Scan identifies specific issues with effort estimates.
Reading time: 23 minutes
What you’ll learn:
- Quick win fixes with highest ROI: compress hero image (30-60 min for 50-70% LCP improvement), add image dimensions (1-2 hours for 60-80% CLS improvement), defer analytics scripts (30-60 min for 30-50% INP improvement)
- The complete Core Web Vitals fix workflow: LCP (image compression, WebP conversion, CDN setup), CLS (image dimensions, reserve space for ads/embeds, preload fonts), INP (defer JavaScript, remove unused libraries, lazy-load third-party scripts)
- Why realistic improvement timelines matter: quick wins (2-4 hours) can improve scores 40-60%, comprehensive fixes (10-20 hours) can achieve 60-80% improvement and pass all targets
- Common mistakes that make Core Web Vitals worse: lazy-loading LCP images (delays main content), over-compressing images (quality loss), removing critical JavaScript (breaks functionality)
- Prioritization strategy when time-constrained: fix LCP first (biggest impact, easiest), then CLS, then INP, with re-testing in 7-14 days to account for CDN and browser cache clearing
Timeline: Quick wins (image compression) = 2-4 hours. Comprehensive fixes = 10-20 hours. Re-test in 7-14 days to measure improvement.
Understanding Your Scan Results
What Scan Tells You About Core Web Vitals
Example Scan report:
Core Web Vitals: FAIL
LCP (Largest Contentful Paint): 4.8 seconds
- Target: 2.5s
- Status: FAIL (92% slower than target)
- Primary issue: Hero image 3.2MB uncompressed
CLS (Cumulative Layout Shift): 0.35
- Target: 0.1
- Status: FAIL (3.5x higher than target)
- Primary issue: Images missing width/height attributes
INP (Interaction to Next Paint): 450ms
- Target: 200ms
- Status: FAIL (2.25x slower than target)
- Primary issue: Heavy analytics scripts blocking interactions
How to Fix LCP (Largest Contentful Paint)
What LCP Measures
LCP = Time until largest visible content element loads (usually hero image, headline, or video).
Target: Under 2.5 seconds Good: 2.5-4.0 seconds Poor: Over 4.0 seconds
Quick Win 1: Compress Hero Image (2-4 hours)
Most common LCP issue: Uncompressed hero image.
Example from Scan:
“Hero image (homepage-hero.jpg) is 3.2MB. Target: 300KB max. Reduce file size by 90% to improve LCP from 4.8s to 1.9s.”
Step-by-Step: Compress Hero Image
Step 1: Identify image causing LCP issue
- Scan report lists specific file:
homepage-hero.jpg - Location: Homepage, above-the-fold
Step 2: Compress image
Option A: Use TinyPNG (free, easiest)
- Visit tinypng.com
- Upload
homepage-hero.jpg(3.2MB) - Download compressed version (typically 200-400KB, 80-90% reduction)
Option B: Use Squoosh (more control)
- Visit squoosh.app
- Upload image
- Choose format: WebP (best compression) or JPEG
- Adjust quality slider (75-85 quality balances size vs visual quality)
- Download optimized image
Option C: Command line (ImageMagick)
convert homepage-hero.jpg -quality 80 -resize 1920x1080 homepage-hero-optimized.jpg
Step 3: Replace original image
- Backup original:
homepage-hero-original.jpg - Upload compressed version:
homepage-hero.jpg - Clear CDN cache (if using CDN)
Step 4: Verify improvement
- Run PageSpeed Insights (free Google tool)
- Check LCP score: Should drop from 4.8s to 1.8-2.2s
- Visual check: Image should look identical (compression artifacts minimal at 80% quality)
Effort: 30-60 minutes Impact: LCP improves 50-70% (biggest quick win)
Quick Win 2: Convert Images to WebP (1-2 hours)
WebP format is 25-35% smaller than JPEG with same quality.
Process:
# Convert all JPEG images to WebP
for file in *.jpg; do
cwebp -q 80 "$file" -o "${file%.jpg}.webp"
done
HTML update:
<!-- Before -->
<img src="homepage-hero.jpg" alt="Hero image">
<!-- After (with fallback) -->
<picture>
<source srcset="homepage-hero.webp" type="image/webp">
<img src="homepage-hero.jpg" alt="Hero image">
</picture>
Effort: 1-2 hours (convert images + update HTML) Impact: LCP improves 10-20% (smaller file sizes)
Quick Win 3: Add Lazy Loading (30 minutes)
Lazy loading defers off-screen images (doesn’t affect LCP but reduces overall page weight).
Implementation:
<!-- Add loading="lazy" to images below fold -->
<img src="product-1.jpg" alt="Product" loading="lazy">
<img src="product-2.jpg" alt="Product" loading="lazy">
<!-- Hero image (above fold): NO lazy loading -->
<img src="homepage-hero.jpg" alt="Hero" loading="eager">
Important: Don’t lazy-load LCP image (makes LCP worse).
Effort: 30 minutes (add loading attribute to images) Impact: Reduces initial page load by 30-50% (doesn’t affect LCP directly but improves overall performance)
Long-Term Fix: Use CDN for Images (4-8 hours)
CDN (Content Delivery Network) serves images from geographically close servers.
Recommended CDNs:
- Cloudflare (free tier available)
- AWS CloudFront
- Cloudinary (image-specific, automatic optimization)
Setup (Cloudflare example):
- Sign up for Cloudflare (free)
- Add domain to Cloudflare
- Update DNS nameservers (point to Cloudflare)
- Enable “Auto Minify” (CSS, JavaScript, HTML)
- Enable “Mirage” (automatic image optimization)
Effort: 4-8 hours (initial setup + testing) Impact: LCP improves 20-40% (faster delivery) + global performance boost
How to Fix CLS (Cumulative Layout Shift)
What CLS Measures
CLS = Visual stability (elements jumping around while page loads).
Target: Under 0.1 Good: 0.1-0.25 Poor: Over 0.25
Common causes:
- Images without width/height attributes
- Ads/embeds shifting content
- Web fonts loading late
Quick Win 1: Add Image Dimensions (1-2 hours)
Most common CLS issue: Images without width/height attributes.
Example from Scan:
“890 images missing width/height attributes. Browser doesn’t reserve space, causing layout shift when images load. CLS: 0.35 (target: 0.1).”
Step-by-Step: Add Image Dimensions
Step 1: Identify images missing dimensions
- Scan lists pages with CLS issues
- Common culprits: Product images, blog post images, thumbnails
Step 2: Get image dimensions
Option A: Right-click image in browser
- Right-click → “Inspect”
- Check naturalWidth and naturalHeight in browser console
Option B: Command line
identify homepage-hero.jpg
# Output: homepage-hero.jpg JPEG 1920x1080
Step 3: Add width/height to HTML
Before:
<img src="product-1.jpg" alt="Product">
After:
<img src="product-1.jpg" alt="Product" width="800" height="600">
For responsive images (width scales, maintain aspect ratio):
<img src="product-1.jpg" alt="Product" width="800" height="600" style="max-width: 100%; height: auto;">
CSS alternative:
img {
aspect-ratio: 4/3; /* or attr(width) / attr(height) */
width: 100%;
height: auto;
}
Step 4: Update all images
- Homepage: Add dimensions to hero, feature images
- Product pages: Add dimensions to product images
- Blog: Add dimensions to post images
Effort: 1-2 hours (depending on number of images) Impact: CLS improves 60-80% (biggest CLS fix)
Quick Win 2: Reserve Space for Ads/Embeds (30-60 minutes)
Ads and embeds (YouTube, Twitter) load asynchronously, shifting content.
Fix: Reserve space with CSS
YouTube embed example:
<!-- Before (causes CLS) -->
<iframe src="https://www.youtube.com/embed/VIDEO_ID"></iframe>
<!-- After (reserves 16:9 aspect ratio space) -->
<div style="position: relative; padding-bottom: 56.25%; height: 0;">
<iframe
src="https://www.youtube.com/embed/VIDEO_ID"
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"
></iframe>
</div>
Ad placeholder example:
<!-- Reserve 300x250 ad space -->
<div style="width: 300px; height: 250px; background: #f0f0f0;">
<!-- Ad loads here asynchronously -->
<div id="ad-slot"></div>
</div>
Effort: 30-60 minutes (add wrappers to embeds/ads) Impact: CLS improves 20-40% (eliminates embed-related shifts)
Quick Win 3: Preload Web Fonts (30 minutes)
Web fonts loading late cause text to shift (FOUT: Flash of Unstyled Text).
Fix: Preload critical fonts
Add to <head>:
<link rel="preload" href="/fonts/your-font.woff2" as="font" type="font/woff2" crossorigin>
Use font-display: swap (fallback font while custom loads):
@font-face {
font-family: 'YourFont';
src: url('/fonts/your-font.woff2') format('woff2');
font-display: swap; /* Show fallback font immediately */
}
Effort: 30 minutes Impact: CLS improves 10-20% (reduces font-related shifts)
How to Fix INP (Interaction to Next Paint)
What INP Measures
INP = Responsiveness (time from user interaction to visual feedback).
Target: Under 200ms Good: 200-500ms Poor: Over 500ms
Common causes:
- Heavy JavaScript execution
- Long tasks blocking main thread
- Unoptimized event handlers
Quick Win 1: Defer Non-Critical JavaScript (1-2 hours)
Heavy JavaScript blocks main thread, making page unresponsive.
Example from Scan:
“Analytics scripts (Google Analytics, Facebook Pixel, Hotjar) loading synchronously. Total 450KB JavaScript blocking interactions. INP: 450ms (target: 200ms).”
Step-by-Step: Defer JavaScript
Step 1: Identify blocking scripts
- Scan lists specific scripts (analytics, chat widgets, tracking pixels)
Step 2: Add defer or async attributes
Before (blocks page load):
<script src="analytics.js"></script>
<script src="facebook-pixel.js"></script>
After (defers execution):
<script src="analytics.js" defer></script>
<script src="facebook-pixel.js" defer></script>
Or use async (downloads in background, executes when ready):
<script src="analytics.js" async></script>
Defer vs Async:
- defer: Executes in order after HTML parsed (use for scripts with dependencies)
- async: Executes as soon as downloaded (use for independent scripts like analytics)
Step 3: Move scripts to footer
<!-- Before (in <head>) -->
<head>
<script src="analytics.js"></script>
</head>
<!-- After (before </body>) -->
<body>
<!-- Page content -->
<script src="analytics.js" defer></script>
</body>
Effort: 1-2 hours (update script tags + test) Impact: INP improves 30-50% (main thread freed up)
Quick Win 2: Remove Unused JavaScript (2-4 hours)
Scan identifies unused JavaScript (code loaded but never executed).
Example from Scan:
“520KB unused JavaScript detected. Coverage: 38% (62% of code never runs).”
Common culprits:
- Old libraries (jQuery loaded but not used)
- Unused plugins (slider library on pages without sliders)
- Redundant analytics (3 different tracking scripts)
Step-by-Step: Remove Unused JavaScript
Step 1: Use Chrome DevTools Coverage tool
- Open Chrome DevTools → More Tools → Coverage
- Reload page
- Check JavaScript usage (red = unused, green = used)
Step 2: Remove or lazy-load unused libraries
Example: jQuery loaded globally but only used on contact page
Before:
<!-- Every page loads jQuery -->
<script src="jquery.min.js"></script>
After:
<!-- Only contact page loads jQuery -->
{% if page.slug == 'contact' %}
<script src="jquery.min.js" defer></script>
{% endif %}
Step 3: Audit plugins
- Remove slider library if no sliders on page
- Remove animation libraries if not used
- Consolidate analytics (don’t need Google Analytics + Mixpanel + Hotjar + Facebook Pixel all at once)
Effort: 2-4 hours (audit + remove scripts) Impact: INP improves 20-40% (less code to parse/execute)
Quick Win 3: Lazy Load Third-Party Scripts (1-2 hours)
Third-party scripts (chat widgets, reviews, social embeds) slow interactions.
Fix: Load on user interaction
Example: Lazy load chat widget
Before (loads immediately):
<script src="//chat-widget.com/widget.js"></script>
After (loads on user scroll or click):
<script>
// Load chat widget only when user scrolls 50%
window.addEventListener('scroll', function() {
if (window.scrollY > document.body.scrollHeight * 0.5) {
const script = document.createElement('script');
script.src = '//chat-widget.com/widget.js';
document.body.appendChild(script);
}
}, { once: true });
</script>
Effort: 1-2 hours (wrap third-party scripts in lazy loaders) Impact: INP improves 20-30% (main thread not blocked immediately)
Re-Testing Core Web Vitals
How Soon to Re-Test
Wait 7-14 days after implementing fixes before re-testing.
Why wait?
- Google’s CrUX (Chrome User Experience Report) data lags 28 days
- CDN caches take 1-7 days to clear
- Browser caches need to expire
Re-test with:
- Scan Pro ($50): Tests live site with real devices
- PageSpeed Insights (free): Google’s official tool
- WebPageTest (free): Detailed waterfall analysis
Expected Improvements
Realistic improvement timeline:
Quick wins (2-4 hours effort):
- LCP: 4.8s → 2.2s (54% improvement)
- CLS: 0.35 → 0.15 (57% improvement)
- INP: 450ms → 280ms (38% improvement)
Comprehensive fixes (10-20 hours effort):
- LCP: 4.8s → 1.8s (62% improvement)
- CLS: 0.35 → 0.08 (77% improvement)
- INP: 450ms → 180ms (60% improvement)
All metrics passing (under targets):
- LCP under 2.5s: PASS
- CLS under 0.1: PASS
- INP under 200ms: PASS
Prioritization: Which Fix First?
If You Have Limited Time (2-4 hours)
Priority 1: Compress hero image (LCP)
- Effort: 30-60 minutes
- Impact: 50-70% LCP improvement
Priority 2: Add image dimensions (CLS)
- Effort: 1-2 hours
- Impact: 60-80% CLS improvement
Priority 3: Defer analytics scripts (INP)
- Effort: 30-60 minutes
- Impact: 30-50% INP improvement
Total effort: 2-4 hours Result: Core Web Vitals likely pass (all metrics under targets)
If You Have More Time (10-20 hours)
Week 1: LCP fixes
- Compress all images (2-4 hours)
- Convert to WebP (1-2 hours)
- Set up CDN (4-8 hours)
Week 2: CLS fixes
- Add image dimensions to all pages (2-4 hours)
- Reserve space for ads/embeds (1-2 hours)
- Preload web fonts (30 minutes)
Week 3: INP fixes
- Defer/async all JavaScript (1-2 hours)
- Remove unused JavaScript (2-4 hours)
- Lazy load third-party scripts (1-2 hours)
Week 4: Re-test and fine-tune
- Run Scan Pro, PageSpeed Insights
- Identify remaining issues
- Optimize edge cases
Total effort: 15-25 hours Result: Core Web Vitals excellent (top 25% of web)
Common Mistakes to Avoid
Mistake 1: Lazy-Loading LCP Image
Don’t do this:
<img src="hero.jpg" alt="Hero" loading="lazy">
Problem: Delays LCP (browser waits to load image).
Fix: Use loading="eager" for above-fold images:
<img src="hero.jpg" alt="Hero" loading="eager">
Mistake 2: Over-Compressing Images
Problem: Compressing images to 10KB makes them blurry.
Balance: Aim for 80-85% JPEG quality (visually identical, 70-80% file size reduction).
Test: Compare original vs compressed side-by-side. If you can see quality loss, increase compression quality.
Mistake 3: Removing Critical JavaScript
Problem: Deferring jQuery breaks site functionality.
Fix: Only defer non-critical scripts (analytics, chat widgets). Keep functional scripts in <head>.
The Bottom Line
Core Web Vitals are Google’s performance metrics (LCP, CLS, INP). Scan identifies specific issues with effort estimates.
Quick wins (2-4 hours):
- Compress hero image (LCP)
- Add image dimensions (CLS)
- Defer analytics scripts (INP)
Comprehensive fixes (10-20 hours):
- Convert images to WebP, set up CDN (LCP)
- Reserve space for embeds, preload fonts (CLS)
- Remove unused JavaScript, lazy-load third-party scripts (INP)
Re-test in 7-14 days with Scan or PageSpeed Insights to measure improvement.
Frequently Asked Questions
How do I know which Core Web Vitals fix to prioritize?
Check your Scan report for which metric is furthest from target:
Example:
- LCP: 4.8s (target 2.5s) = 92% over target
- CLS: 0.15 (target 0.1) = 50% over target
- INP: 280ms (target 200ms) = 40% over target
Prioritize LCP (furthest from target, biggest impact).
General rule: Fix LCP first (usually easiest, highest ROI), then CLS, then INP.
Will fixing Core Web Vitals improve my Google rankings?
Yes, but indirectly.
Core Web Vitals are ranking factor (confirmed by Google), but:
- Small weight: CWV is one of 200+ ranking factors
- Tiebreaker: If two sites have equal content quality, faster site ranks higher
- Not magic: Won’t fix fundamental SEO issues (thin content, no backlinks)
Better reason to fix CWV: User experience. Faster sites have:
- 20-30% lower bounce rate
- 10-20% higher conversion rate
- Better mobile experience
ROI is conversions, not just rankings.
Can I pass Core Web Vitals without a developer?
Partially. Some fixes require technical skills:
No-code fixes (you can do):
- Compress images with TinyPNG
- Add lazy loading attribute to images
- Remove unused plugins
Developer-required fixes:
- Setting up CDN
- Removing unused JavaScript
- Optimizing server response time
- Code splitting
If non-technical: Focus on image compression (biggest quick win). Hire developer for comprehensive fixes (budget $500-1500).
How often should I check Core Web Vitals?
Quarterly (every 90 days) for most sites.
More frequently if:
- E-commerce site (performance = revenue)
- High-traffic site (thousands of daily visitors)
- Recently migrated or redesigned (validate changes)
Less frequently if:
- Low-traffic site (under 1000 monthly visitors)
- Static site (minimal code changes)
Cost: $25 or $50/quarter for Scan = $100-200/year (performance monitoring).
What’s a good Core Web Vitals score?
All metrics passing (under targets):
- LCP under 2.5s
- CLS under 0.1
- INP under 200ms
Percentile benchmarks:
- Top 25% of web: LCP 1.8s, CLS 0.05, INP 150ms
- Top 50% of web: LCP 2.4s, CLS 0.09, INP 190ms
- Bottom 50% of web: LCP 3.5s+, CLS 0.2+, INP 300ms+
Goal: Pass all three metrics (under targets). Reaching top 25% requires significant optimization effort (20-40 hours).
Can Core Web Vitals get worse over time?
Yes, if:
- New features added (more JavaScript, larger images)
- Third-party scripts added (chat widgets, analytics)
- Content accumulates (blog posts with unoptimized images)
Prevention: Run Scan quarterly, catch regressions early.
Example regression:
- Month 0: LCP 2.2s (passing)
- Month 6: Added chat widget, new analytics tool
- Month 6: LCP 3.8s (failing)
- Fix: Lazy-load chat widget, defer analytics → LCP back to 2.3s
Do mobile and desktop have different Core Web Vitals?
Yes. Mobile is typically 30-50% slower than desktop.
Example:
- Desktop LCP: 1.8s (good)
- Mobile LCP: 3.2s (poor)
Why?
- Mobile has slower CPUs (JavaScript takes longer)
- Mobile has slower network (images take longer)
- Mobile has less memory (more resource contention)
Google uses mobile-first indexing, so prioritize mobile performance.
Scan tests both mobile and desktop, shows metrics for each.
What if I fix Core Web Vitals but Scan score is still low?
Scan overall score includes more than Core Web Vitals:
- Technical SEO (broken links, missing schema)
- Accessibility (WCAG violations)
- Security (HTTPS issues)
- Mobile optimization
CWV is about 30% of Scan score. Fixing CWV improves score from 42 → 58 (example), but won’t reach 90+ without fixing other categories.
Focus areas (if CWV passing but score low):
- Add schema markup (Technical SEO)
- Fix accessibility violations (Accessibility)
- Add security headers (Security)
Ready to fix Core Web Vitals? Run Scan ($25 or $50) to identify specific issues, then implement quick wins (image compression, image dimensions, defer scripts) in 2-4 hours.
Was this helpful?
Thanks for your feedback!
Have suggestions for improvement?
Tell us moreHelp Us Improve This Article
Know a better way to explain this? Have a real-world example or tip to share?
Contribute and earn credits:
- Submit: Get $25 credit (Signal, Scan, or Solutions)
- If accepted: Get an additional $25 credit ($50 total)
- Plus: Byline credit on this article