How to Fix LCP (Largest Contentful Paint) Without Losing Your Mind

Your LCP is probably slow because of one image. Seriously. One. Let's find it and fix it before Google notices.

Illustration showing Largest Contentful Paint speedometer reaching a fast score with browser loading a hero image

Here's something that keeps annoying me. People spend weeks debugging their LCP score, reading Google's documentation three times over, running Lighthouse twelve times in a row hoping for a different number. And most of the time? It's one image. Their hero image is 2.4MB, served as a PNG, loaded without any priority hint. That's it. That's the whole mystery.

I'm not saying LCP is always simple. Sometimes it's messy. But 7 out of 10 times, fixing Largest Contentful Paint comes down to a handful of very specific things that take maybe an afternoon to sort out.

What LCP Actually Measures (Quick Version)

LCP tracks how long it takes for the biggest visible thing on your page to finish rendering. "Biggest visible thing" usually means your hero image, a large heading, or a big background image. Google picks the element that takes up the most pixels in the viewport.

LCP Thresholds (What Google Actually Uses)

Good: Under 2.5 seconds

Needs Improvement: 2.5 to 4 seconds

Poor: Over 4 seconds

Google uses the 75th percentile from Chrome User Experience Report (CrUX) field data. Your Lighthouse lab score does NOT determine rankings. Real user data does.

Quick tip before we go further: run your site through VitalsFixer or PageSpeed Insights and look at the filmstrip. Find the frame where your biggest element appears. That's your LCP moment. Everything we're about to do is about making that moment happen sooner.

Step 1: Find Your LCP Element

You can't fix something if you don't know what it is. Open PageSpeed Insights, run your URL, and scroll down to the "Largest Contentful Paint element" diagnostic. It'll tell you exactly which element is your LCP.

For most websites it's one of these:

If it's an image, keep reading. If it's text, skip to the server response section because your issue is probably TTFB or render-blocking CSS.

Step 2: Fix Your Hero Image (The Big One)

Here's where most LCP problems live. Your hero image is too big, wrong format, loaded wrong, or all three at once.

Convert to WebP (or AVIF)

If your hero image is a JPEG or PNG, you're leaving performance on the table. WebP gives you roughly 25-35% smaller files at the same visual quality. AVIF pushes that to 40-50% but browser support still isn't universal.

Easiest way to convert: open Squoosh.app, drop your image in, pick WebP, set quality to 75-80, and compare. If it looks the same to your eyes, ship it.

Real Numbers From a Real Site

A client's hero image was a 1.8MB JPEG at 2400x1600. After converting to WebP at quality 78 and resizing to 1200x800 (which matched their actual display size), it was 127KB. LCP went from 4.1s to 1.9s. Same image. Same quality. Just, you know, not insane file size anymore.

Add fetchpriority="high"

This is probably the single most underused attribute in web development. Adding fetchpriority="high" to your hero image tells the browser "download this before anything else." Without it the browser treats your hero the same as every other image on the page.

<img src="hero.webp"
     alt="Your hero image description"
     width="1200" height="600"
     fetchpriority="high"
     decoding="async">

That one attribute can cut 200-500ms off your LCP. And you'll see it immediately in Lighthouse.

Do NOT Lazy Load Your Hero Image

This is the mistake I see every single week. Some plugin or framework adds loading="lazy" to every image on the page, including the hero. That means the browser won't even start downloading your LCP element until it scrolls into view. Which is immediately, because it's at the top of the page. But the browser doesn't know that yet.

The Rule

Above-the-fold images: loading="eager" or just don't set the attribute at all.

Below-the-fold images: loading="lazy"

If you're using WordPress and WP Rocket or a similar plugin, check the settings. Most of them have an "exclude above-the-fold images" option. Turn it on.

Preload the Hero Image

For maximum speed, add a preload hint in your <head>. This makes the browser start downloading the image before it even parses the HTML where the image tag lives:

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

This is especially useful when your hero image URL is buried deep in the HTML or loaded via CSS background-image (where the browser can't discover it until it parses the CSS).

Size Your Images Properly

If your image displays at 600px wide on screen, don't serve a 3000px wide original. Use srcset to serve different sizes for different screen widths:

<img src="hero-800.webp"
     srcset="hero-400.webp 400w,
             hero-800.webp 800w,
             hero-1200.webp 1200w"
     sizes="(max-width: 600px) 100vw, 800px"
     alt="Hero description"
     width="800" height="400"
     fetchpriority="high"
     decoding="async">

Mobile users on 4G connections will get the 400px version instead of the 1200px version. That alone could save 60-70% of bytes on mobile.

Step 3: Fix Your Server Response Time (TTFB)

Time to First Byte is how long it takes your server to start sending the HTML back to the browser after a request. If your TTFB is over 800ms, no amount of image optimization will save you because the browser can't even start loading your page for almost a full second.

Common TTFB Problems

How to Fix TTFB

First, check your TTFB in Chrome DevTools. Open Network tab, load your page, click the main document request. Under "Timing" you'll see "Waiting for server response." If it's over 600ms, you've got a problem.

Quick wins:

If you're on WordPress and your TTFB is over a second? Your hosting is the problem. No plugin will fix bad hardware. I know nobody wants to hear that, but it's the truth about 80% of the time.

Step 4: Kill Render-Blocking Resources

Your browser can't paint anything until it finishes downloading and parsing all CSS files in the <head>. If you've got 6 external stylesheets loading before the body, your LCP has to wait for every single one of them.

CSS Fixes

JavaScript Fixes

Add defer to every script that isn't absolutely needed for the initial render:

<!-- Bad: blocks rendering -->
<script src="analytics.js"></script>

<!-- Good: loads after HTML is parsed -->
<script src="analytics.js" defer></script>

Analytics, chat widgets, social embeds, tracking pixels. None of these need to load before your hero image appears on screen. Defer them all. For a deeper look at this, check out our JavaScript defer guide.

Step 5: Font Loading

Custom fonts can block text rendering, and if your LCP element is a heading, that's your LCP waiting on a font file to download.

Two fixes that work immediately:

/* In your @font-face declaration */
@font-face {
    font-family: 'YourFont';
    src: url('font.woff2') format('woff2');
    font-display: swap;  /* Show fallback text immediately */
}

And preload your most important font file:

<link rel="preload" as="font" type="font/woff2"
      href="/fonts/main.woff2" crossorigin>

font-display: swap means the browser shows your text in a system font immediately, then swaps in the custom font when it's ready. Users see content faster, LCP fires earlier. Win win.

Step 6: Use a CDN

If your server is in New York and a user is in Tokyo, that's about 200ms of network latency just for the round trip. Multiply that by every resource on your page. A CDN caches your files on servers around the world so users always hit a nearby copy.

Cloudflare's free tier is enough for most websites. Set it up, enable caching, and watch your global TTFB drop by 50-80%. For images specifically, if you're using Cloudflare, their Polish feature will automatically convert images to WebP for supporting browsers.

The LCP Fix Checklist

Run Through This Before You Deploy

1. Hero image is WebP (or AVIF), under 150KB

2. Hero image has fetchpriority="high"

3. Hero image is NOT lazy loaded

4. Hero image is preloaded in the head

5. No render-blocking CSS or JS in the head

6. TTFB is under 600ms

7. Fonts use font-display: swap

8. CDN is serving static assets

9. Images use srcset for responsive sizes

10. Width and height attributes set on all images (prevents CLS too)

What About WordPress?

WordPress has some LCP quirks that catch people off guard:

We've got a dedicated WordPress Core Web Vitals Guide if you want the full breakdown with plugin recommendations and all that.

FAQ

What's a good LCP score?

Under 2.5 seconds. Google uses the 75th percentile of real field data (CrUX) to decide if you pass or fail. Your Lighthouse lab score is useful for debugging but it's not what affects rankings.

My LCP keeps changing between tests. Is that normal?

Totally normal. Lab tools test from a single server at a single moment. Network conditions, server load, and even what other tabs you have open can change the number. Focus on field data trends over time, not individual lab runs.

Does fetchpriority="high" really make a difference?

Yes. We consistently see 200-500ms improvement just from this one attribute. The browser normally downloads images in the order it discovers them. fetchpriority tells it "this one matters most, grab it first."

Should I lazy load my hero image?

No. Absolutely not. Never. Your hero image is the LCP element. Lazy loading it delays its download. Remove loading="lazy" from any above-the-fold image.

How much does switching to WebP help LCP?

For a typical hero image, switching from JPEG to WebP saves 25-35% of the file size. On a slow connection, that translates to 300-800ms faster LCP. It's one of the easiest wins you can get.

Find Your LCP Problem in 30 Seconds

Run your site through VitalsFixer. We'll show you exactly what your LCP element is, how big it is, and what's blocking it from loading faster.

Analyze My Site Free →

Too busy to fix this yourself?

Our engineers fix LCP, CLS, and INP on your site directly. Real humans, not automated tools. 48-hour turnaround. If we can't improve your scores, you get your money back.

View Expert Fix Service →