How to Reduce LCP Below 2.5s with Image Optimization

Your LCP element is probably an image. Here's how to find it, optimize it, and get your Largest Contentful Paint under Google's 2.5-second threshold.

Cristian Peña5 min read
LCPPerformanceCore Web VitalsLighthouse

Your LCP is probably an image

Largest Contentful Paint measures how long it takes for the biggest visible element on your page to finish rendering. On most websites, that element is an image — a hero banner, a product photo, or a background image.

Google considers LCP "good" at under 2.5 seconds, "needs improvement" at 2.5-4 seconds, and "poor" above 4 seconds. As of 2026, about 34% of websites fail this threshold, and images are the primary cause.

The good news: image optimization is the highest-leverage fix you can make. A single well-optimized hero image can shave 1-3 seconds off your LCP.

Step 1: Find your LCP element

Before optimizing anything, you need to know which element is actually your LCP. Don't guess.

Using Chrome DevTools:

  1. Open DevTools (F12)
  2. Go to the Performance tab
  3. Click the record button, reload the page, then stop recording
  4. Look for the "LCP" marker in the timeline — it highlights the exact element

For detailed guidance on using Chrome DevTools for performance analysis, see the official Chrome documentation.

Using PageSpeed Insights: Enter your URL at pagespeed.web.dev. Scroll to the "Diagnostics" section and find "Largest Contentful Paint element." It tells you exactly what it is.

In most cases, it's one of these: a hero/banner image, a product featured image, a background image set via CSS, or a large text block (less common).

Check both mobile and desktop — your LCP element might be different on each. Mobile typically has a worse LCP because of slower connections and smaller caches.

Step 2: Optimize the LCP image itself

Once you know which image is the LCP element, optimize it aggressively.

Compress it

Convert to WebP at quality 75-85. This alone reduces file size by 25-34% compared to JPEG, with no visible quality difference.

For a typical hero image (1200×600), you should be targeting under 100KB. If your hero image is over 200KB, there's room to improve.

Resize it

Serve exactly the dimensions you need. If your hero displays at 1200px wide on desktop and 400px on mobile, don't serve a 3000px original to everyone.

<img
  src="/hero-1200.webp"
  srcset="/hero-400.webp 400w, /hero-800.webp 800w, /hero-1200.webp 1200w"
  sizes="(max-width: 480px) 400px, (max-width: 1024px) 800px, 1200px"
  alt="Hero"
  width="1200"
  height="600"
  loading="eager"
  fetchpriority="high"
/>

Step 3: Deliver it faster

Even a perfectly compressed image can have slow LCP if the delivery is slow.

Preload the LCP image

Add this to your <head>. It tells the browser to start downloading the image immediately, before it even parses the CSS:

<link
  rel="preload"
  as="image"
  href="/hero-1200.webp"
  fetchpriority="high"
  type="image/webp"
/>

Avoid CSS background images for LCP

If your LCP element is set via background-image in CSS, the browser can't discover it until the CSS is parsed and applied. Move it to an <img> tag with fetchpriority="high" instead.

Use a CDN

Serving images from a CDN reduces latency by serving from the closest geographic location. Most hosting providers (Vercel, Cloudflare, Netlify) include CDN by default.

Enable compression

Make sure your server sends images with proper compression headers:

Content-Encoding: br  (Brotli, preferred)
Content-Encoding: gzip  (fallback)
Cache-Control: public, max-age=31536000, immutable

The immutable cache directive tells browsers the file won't change, avoiding unnecessary revalidation requests.

Step 4: Don't block the render

Your image loads fast, but other resources might be blocking it.

Defer non-critical JavaScript

Every render-blocking script delays your LCP. Move non-critical scripts to defer or async:

<!-- Render-blocking (bad for LCP) -->
<script src="/analytics.js"></script>

<!-- Non-blocking (good for LCP) -->
<script src="/analytics.js" defer></script>

Inline critical CSS

If your above-the-fold styles are in an external stylesheet, the browser has to download and parse it before rendering anything. Inline the critical CSS for the hero section directly in <style> tags.

Common mistakes that kill LCP

Lazy loading the LCP image. The loading="lazy" attribute tells the browser to deprioritize the image. Never use it on your LCP element. Use loading="eager" instead (or omit the attribute entirely, since eager is the default).

Using a carousel/slider as the hero. Carousels often load JavaScript before rendering the first image, adding unnecessary delay. A static hero image with good compression will always be faster.

Serving from a different origin. If your image is on images.example.com but your page is on example.com, the browser needs an additional DNS lookup and TLS handshake. Use the same origin or preconnect:

<link rel="preconnect" href="https://images.example.com" />

Measuring improvement

After making changes, test again:

  1. Run PageSpeed Insights 3 times and average the results (lab scores vary between runs)
  2. Check the Chrome UX Report data in Search Console (this is real user data, and what Google actually uses for rankings)
  3. Monitor over 28 days — CrUX data is based on a rolling 28-day window

For more details on LCP thresholds and measurement techniques, see Google's LCP documentation.

Target: LCP under 2.5s on mobile with a slow 3G connection. If you hit that, you're in good shape for any connection speed.

Compress your LCP image now

Convert to WebP and resize in seconds — free, in your browser, no uploads.

Get Started