Skip to content
CWV Checker

How to fix a slow LCP

LCP measures when your main content appears. Here's how to find what's slow and the fixes that actually move it, in order of effect.

What LCP is actually timing

Largest Contentful Paint is the moment the biggest visible element in the viewport finishes rendering. Usually that is a hero image, a background image, a video poster frame, or a large block of heading text. It is a proxy for the question your visitor is really asking: has this page loaded yet?

The element is chosen by area as it appears on first load, so it can change between devices. On a phone your LCP element is often not the same one as on desktop, which is why testing mobile matters.

Break the time down before you fix anything

Google splits LCP into four consecutive parts, and they need completely different fixes. Working out which part is large is the whole job:

  1. Time to first byte. Your server thinking. If this is over 600ms, nothing else you do to the image matters much — fix the server first.
  2. Resource load delay. The gap between the HTML arriving and the browser starting to download the LCP image. This is almost always a discovery problem: the image is set in CSS, injected by JavaScript, or sitting behind a lazy-loader, so the browser does not know it needs it until far too late.
  3. Resource load time. Downloading the image itself. This is a file size problem, and it is the one people assume they have.
  4. Element render delay. The image has arrived but cannot paint, usually because a font or a render-blocking stylesheet is still outstanding.

Fixes, in the order they pay off

1. Make the LCP image discoverable in the HTML

The browser’s preload scanner reads the raw HTML before anything executes. If your hero is a real <img> tag with a src, it starts downloading immediately. If it is a CSS background-image, the browser has to download and parse the stylesheet first, and if a script inserts it, later still.

<img src="/hero.avif" width="1200" height="675"
     alt="…" fetchpriority="high" />

If it genuinely has to stay a background image, preload it explicitly: <link rel="preload" as="image" href="/hero.avif" fetchpriority="high">

2. Never lazy-load it

Remove loading="lazy" from anything in the first viewport. On WordPress, most performance plugins have an “exclude above-the-fold images” setting, and it is usually off by default.

3. Cut the file size properly

Serve AVIF or WebP with a JPEG fallback, and size the file for the device rather than shipping one 2400px original to everyone. A hero that arrives as 1.4 MB and should be 120 KB is not a rounding error — on a throttled 4G connection that difference alone is well over a second.

<img src="/hero-1200.jpg"
     srcset="/hero-600.avif 600w, /hero-1200.avif 1200w, /hero-2400.avif 2400w"
     sizes="(max-width: 700px) 100vw, 1200px"
     width="1200" height="675" alt="…" fetchpriority="high" />

4. Stop fonts holding the paint hostage

If your LCP element is text, a web font that blocks rendering blocks LCP. font-display: swap plus a preload of the one font file you actually need above the fold fixes it. Self-host rather than pulling from a third-party domain: that saves a DNS lookup, a TCP handshake and a TLS negotiation before the first byte of font data.

5. Get the render-blocking CSS out of the way

See the render-blocking guide. Even a perfectly optimised image cannot paint while the browser is waiting on a stylesheet.

What does not work

  • Buying faster hosting when your TTFB is already fine. If your server replies in 200ms, a more expensive server will reply in 190ms. Look at the image.
  • Preloading everything. Preload is a priority instruction. Preloading six things tells the browser that nothing is important.
  • Optimising the Lighthouse score directly. Deferring a script to make a specific audit go green often moves work later without removing it, so the number improves and your visitors do not.

Common questions

What counts as a good LCP?
2.5 seconds or less at the 75th percentile of real visits. Between 2.5 and 4 seconds needs work; over 4 seconds is poor. The 75th percentile matters: it means a quarter of your visitors can be having a worse time than your own testing suggests.
My LCP is fine in the lab but bad in the field. Why?
The lab test runs from one location on a simulated connection with an empty cache. Your real visitors are spread across networks, devices and geography, and the slowest quarter of them sets your field score. A big gap usually means either slow server response for distant visitors — a CDN problem — or a very heavy page that only hurts on weaker phones.
Does lazy-loading images help LCP?
For images below the fold, yes. For the LCP element itself it is actively harmful: loading="lazy" tells the browser to deprioritise the single thing your visitor is waiting for. This is one of the most common self-inflicted LCP problems on WordPress sites, where a plugin lazy-loads everything indiscriminately.
Do I need to switch to a static site to fix this?
Almost never. Most bad LCP is one oversized image and a slow first byte. Rebuilding the site is the most expensive possible response to a problem that is usually two afternoons of work.

Check a page against this

Free, no signup, no ads. We keep nothing except the shareable result, for 30 days.

Enter any public URL. You’ll get the one change that recovers the most load time, what it’s worth, and the measurements underneath.

Other guides