ImagePDF.Tools
Performance & SEO

How to Pass Core Web Vitals with Optimized Images

N
NikolaLast updated on June 19, 2026 · 9 min read

Summary

Images cause 70% of LCP failures. This step-by-step guide diagnoses and fixes image-related Core Web Vitals issues to improve your Google ranking.

Your Google ranking now depends on how fast your pages feel to real users, not just to a Lighthouse audit. Core Web Vitals are the three signals Google uses to measure that experience: LCP (Largest Contentful Paint), INP (Interaction to Next Paint), and CLS (Cumulative Layout Shift). Images are the primary driver of poor scores across all three.

LCP measures how long before the biggest visible element loads. Images are the LCP element on roughly 70% of pages. CLS measures unexpected layout shifts, images without declared dimensions are a top cause. INP measures responsiveness, rendering large unoptimised images on the main thread can block interaction. Get your images right and you've solved most of your Core Web Vitals problem in one move.

This guide is a step-by-step diagnostic and fix process. Work through each step in order, most sites see their biggest gain from steps 1–3. If you want to start with the quick win, compress your images to the right size and format first.

Core Web Vitals: LCP, CLS and INP metric cards with Good, Needs Improvement, Poor thresholds | ImagePDF.Tools
Google measures three Core Web Vitals, images are the primary driver of failures in all three.

Understanding the Three Core Web Vitals

MetricWhat It MeasuresGood ThresholdImage's Role
LCPLargest visible element load time< 2.5 sPrimary cause, image is LCP element on 70% of pages
CLSUnexpected layout shift magnitude< 0.1Images without width/height cause layout shifts
INPDelay from user interaction to response< 200 msDecoding large images on main thread blocks interaction
Core Web Vitals thresholds and image's role in each

Step 1: Identify Your LCP Element

Before you can fix LCP, you need to know which element is causing it. Run this snippet in your browser console on the page you want to diagnose:

javascript
// 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 });

Alternatively, run Lighthouse in Chrome DevTools → Performance Insights panel → look for the orange LCP marker on the filmstrip. If the LCP element is an image (which it is on most pages), proceed to step 2. If it's a text block, the fixes are different, focus on font loading and server response time instead.

Step 2: Diagnose the Image Bottleneck

With your LCP image identified, open Chrome DevTools → Network tab → filter by "Img" → click the image request. Look for these four failure patterns:

  • File size over 100 KB on mobile: compress it, right-size it for the render width, or switch to WebP/AVIF.
  • Format is JPEG or PNG: almost always compressible further without perceptible quality loss at screen resolution.
  • "Queued at" timestamp is past 500 ms: the image is being discovered too late in the waterfall, it's either lazy-loaded incorrectly or buried in a CSS file.
  • Initiator is a .css file: CSS background-image is invisible to the browser preload scanner and always discovered late.
⚠️

CSS background-image is the single most common cause of avoidable LCP failures. The browser preload scanner cannot see background images declared in stylesheets. Move your hero image to an <img> tag with fetchpriority="high" and you will see an immediate improvement on most sites.

Step 3: Right-Size the Image for Each Viewport

Serving a 3,000×2,000 px image that renders at 390×260 px on a mobile screen wastes 99% of the bytes transferred. The browser has to download and decode all of them regardless. Calculate the correct source dimensions:

javascript
// Correct source width = render width × device pixel ratio
const renderWidth = element.getBoundingClientRect().width;
const targetWidth = Math.round(renderWidth * window.devicePixelRatio);
// Example: 390px container on a 2× screen → 780px source image is sufficient

// Serve the right size to each device automatically with srcset:
// <img srcset="img-780w.webp 780w, img-1560w.webp 1560w" sizes="100vw">

For responsive images, generate at least two breakpoints: one for mobile (1×) and one for desktop retina (2×). Use the sizes attribute to tell the browser the render width at each breakpoint, this is what allows it to pick the right srcset entry before layout is calculated.

Step 4: Compress to the Optimal Quality Setting

File size after right-sizing is a function of both resolution and compression quality. Use these quality targets as your starting point:

FormatQuality SettingTypical Size (1200×800)Notes
JPEG75–8060–120 KBVisually lossless at screen resolution for most photos
WebP (lossy)75–8040–90 KBEquivalent to JPEG 85 at ~25% smaller size
AVIF60–7030–70 KBBest compression; slower to encode
PNGLossless / compression 9100–400 KBOnly for hard-edge content (screenshots, logos)
WebP (lossless)N/A80–300 KBFor transparency without PNG size penalty
Recommended compression quality by format
💡

Never re-encode an already-compressed JPEG. Every encode cycle adds generation loss even at quality 95. Always compress from the original source file.

Step 5: Preload the LCP Image

Even a perfectly compressed image will fail LCP if the browser discovers it late. Preloading tells the browser to fetch the LCP image immediately on HTML parse, before it even starts processing stylesheets or scripts:

html
<!-- In <head>, fetched immediately on HTML 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> tag itself -->
<img src="/images/hero.webp"
     srcset="/images/hero-780w.webp 780w, /images/hero-1560w.webp 1560w"
     sizes="100vw"
     fetchpriority="high"
     decoding="async"
     width="1560" height="1040"
     alt="Hero">

Step 6: Fix CLS by Declaring Image Dimensions

Every image without explicit width and height attributes causes a layout shift as the browser loads it and the page reflows. This directly harms your CLS score.

Always declare both attributes on every <img> tag, even for images with CSS max-width: 100%. The browser uses the declared aspect ratio to reserve the right amount of space before the image loads, preventing the shift entirely.

Step 7: Decode Off the Main Thread

Large images decoded synchronously on the main thread block user interactions, contributing to poor INP. Adding decoding="async" tells the browser to decode the image in a separate thread, keeping the main thread available for user input. Add it to every image that is not the LCP image.

ℹ️

Do NOT add decoding="async" to your LCP image. Async decoding can delay when the browser paints the element, increasing LCP time. Use it on secondary images only.

Step 8: Lazy-Load Below-the-Fold Images

Images below the fold that load eagerly on every page view consume bandwidth and delay the LCP image. Add loading="lazy" to any image that is not visible in the initial viewport. Do not add it to the LCP image, it will delay its load.

For more detail on how lazy loading interacts with LCP, read our post on the most common lazy-loading mistake that hurts LCP.

Measuring the Impact

After making changes, measure with PageSpeed Insights (which includes real-user Chrome data from the CrUX dataset) rather than Lighthouse alone. Lighthouse is simulated; PageSpeed Insights shows how real users on your actual traffic are experiencing the page.

Moving LCP from 3.2 s to under 2.5 s moves you from "Needs Improvement" to "Good", a meaningful ranking signal change. Moving below 2.0 s typically produces a measurable improvement in organic search rankings within 2–4 weeks as Googlebot re-crawls your pages.

The Bottom Line

Core Web Vitals failures trace back to images more than any other cause. Right-size, right-format, compress, preload the LCP image, declare dimensions, and lazy-load below the fold. That checklist, applied to the right images on your highest-traffic pages, will move your scores from red to green faster than any other single investment.

Start with the quick win: compress your images to the right quality and convert your hero image to WebP format, both take under a minute.

Frequently asked questions

What is LCP and why do images affect it?
LCP (Largest Contentful Paint) measures how long it takes for the biggest visible element on the page to become fully visible. Images are the LCP element on roughly 70% of pages, so image size, format, and delivery method are the primary drivers of LCP performance.
Should I add loading="lazy" to my hero image?
No. Never add loading="lazy" to your LCP (hero) image. Lazy loading delays the browser from fetching the image until it is about to enter the viewport, which directly increases LCP time. Only add lazy loading to images below the fold.
Does image compression hurt image quality?
At the recommended quality settings (JPEG 75–80, WebP 75–80), the difference is imperceptible to most viewers at screen resolution. You are removing data that the human visual system cannot detect. Always preview the compressed result before publishing.
What is CLS and how do images cause it?
CLS (Cumulative Layout Shift) measures how much page content moves unexpectedly as the page loads. Images without declared width and height attributes cause shifts because the browser doesn't know how much space to reserve before the image loads. Always set width and height on every img element.
How long does it take for Core Web Vitals improvements to affect rankings?
Google's CrUX dataset (which drives PageSpeed Insights and rankings) updates monthly. After deploying improvements, expect ranking effects to appear within 4–8 weeks as Googlebot re-crawls your pages and the CrUX data refreshes.

Sources & references

This article was researched and written by Nikola, drawing on the following primary sources and documentation:

Ready to try it?

All tools run entirely in your browser, no uploads, no account required.

Compress Image
You're offline, cached tools still work