How to Pass Core Web Vitals with Optimized Images
Images are the single biggest contributor to LCP failures. A technical guide to diagnosing and fixing image-related Core Web Vitals issues.
LCP (Largest Contentful Paint) is the most impactful Core Web Vitals signal, and images are the LCP element on roughly 70% of pages. Fixing image delivery is the single highest-leverage change most websites can make for both SEO and user experience.
Step 1: Identify Your LCP Image
// Find the LCP element in the browser console
new PerformanceObserver((list) => {
const last = list.getEntries().at(-1);
console.log('LCP element:', last.element);
console.log('LCP time:', last.startTime.toFixed(0), 'ms');
}).observe({ type: 'largest-contentful-paint', buffered: true });Step 2: Diagnose the Bottleneck
With the LCP image identified, open Chrome DevTools → Network → filter by "Img" → click the image:
- ●Size over 100KB on mobile — compress it, right-size it, or switch to WebP
- ●Format is JPEG or PNG — almost always compressible further without visible quality loss
- ●"Queued at" is past 500ms — the image is being discovered too late in the waterfall
- ●Initiator is a CSS file — CSS
background-imageis invisible to the preload scanner
CSS background-image is invisible to the browser preload scanner. Move hero images to <img> tags with fetchpriority="high" for a guaranteed LCP improvement on most pages.
Step 3: Right-Size the Image
Serving a 3000×2000px image that renders at 390×260px wastes 99% of the bytes downloaded. Calculate the correct source size:
// The right source image width = render width × device pixel ratio
const renderWidth = element.getBoundingClientRect().width;
const targetWidth = Math.round(renderWidth * window.devicePixelRatio);
// 390px container on 2× screen → 780px source image
// Use srcset to serve the right size automatically:
// <img srcset="img-780w.webp 780w, img-1560w.webp 1560w" sizes="100vw">Step 4: Compress to the Right Quality
- ●JPEG quality 75–80 is visually lossless at screen resolution for most photos
- ●WebP quality 75 ≈ JPEG quality 85 at 25% smaller file size
- ●PNG for hard-edge content only (screenshots, logos, line art)
- ●Never re-encode an already-compressed JPEG — every cycle adds generation loss
Step 5: Preload the LCP Image
<!-- In <head> — the browser fetches this immediately on parse -->
<link rel="preload" as="image"
href="/images/hero.webp"
imagesrcset="/images/hero-780w.webp 780w, /images/hero-1560w.webp 1560w"
imagesizes="100vw"
fetchpriority="high"
>
<!-- On the <img> itself -->
<img src="/images/hero.webp" fetchpriority="high" decoding="async"
width="1560" height="1040" alt="Hero">After making changes, measure with PageSpeed Insights (real-user Chrome data) rather than only Lighthouse (simulated). Moving LCP from 3.2s to 2.1s is a measurable ranking improvement. Start by compressing your images with the right quality settings.
Ready to try it?
All tools run entirely in your browser — no uploads, no account required.
Compress Image