Skip to content
Sign in

Fixing Largest Contentful Paint (LCP): a step-by-step diagnosis

LCP measures when the biggest thing on screen appears. Every slow LCP breaks down into four phases, and once you know which phase is slow, the fix is usually obvious.

DeskSEO editorial team · · 6 min read

A sprinter bursts out of the starting blocks on a blue running track

Largest Contentful Paint is the time from when a user starts loading a page until the largest image or text block in the viewport is rendered. It is the Core Web Vital that most closely matches what people mean by "the page loaded". Google considers 2.5 seconds or less good, measured at the 75th percentile of real visits, so three out of four page loads need to hit it.

Most advice about LCP is a list of twenty optimisations to try. That is slow and often wasteful. A better approach is to find the LCP element, split its time into phases, and fix only the phase that is actually slow.

Step 1: find the LCP element

You cannot fix LCP without knowing what the element is, and it is often not what you expect. On a product page it might be the main photo, a promotional banner, or a cookie consent dialog that covers the screen. On an article it might be the headline or the first paragraph rather than the featured image.

  • PageSpeed Insights shows the LCP element for a URL under the diagnostics, along with field data if the page has enough traffic.
  • Chrome DevTools: record a load in the Performance panel and look for the LCP marker; hovering it highlights the element.
  • Real users: the open-source web-vitals JavaScript library can report the LCP element along with the timing from real visits, which is the most reliable source for templates whose LCP varies.

Check on a mid-range phone profile, not just a desktop. The LCP element on mobile is frequently different, because the layout is different.

Step 2: break LCP into four phases

Every LCP time is the sum of four parts. This breakdown, popularised by Chrome's web performance team, is the single most useful idea for fixing it.

PhaseFrom → toTypical share in a healthy page
Time to First Byte (TTFB)Navigation start → first byte of HTMLRoughly 40%
Resource load delayTTFB → browser starts downloading the LCP resourceUnder 10%
Resource load durationDownload start → download endRoughly 40%
Element render delayDownload end → element paintedUnder 10%

For text LCP elements, there is no resource to download, so the time is TTFB plus render delay. PageSpeed Insights and the DevTools Performance panel both show this breakdown for the LCP element. Whichever phase is far larger than its typical share is where the fix is.

Phase 1: slow TTFB

If the HTML takes 1.5 seconds to arrive, no front-end optimisation will get LCP under 2.5 seconds on a phone. Signs of a TTFB problem: the first byte arrives late in the waterfall even on a fast connection, and the delay is similar for every page of a template.

The usual fixes are caching full HTML pages, a CDN in front of the origin, faster database queries, and removing redirects before the page (each redirect adds a full round trip). The server response time guide covers measurement and fixes in detail. The DeskSEO checker measures TTFB on every run, so a regression shows up in the score history.

A four-person pit crew changes a tyre on a race car in a sunlit garage lane

Phase 2: resource load delay

This is the gap between the HTML arriving and the browser starting to download the LCP image. It should be tiny. When it is large, the browser did not know about the image early. Common causes:

  • The image is lazy-loaded. loading="lazy" on the hero image tells the browser to wait. Remove it from the LCP image; keep it for images below the fold.
  • The image is set as a CSS background in a stylesheet. The browser only discovers it after downloading and parsing the CSS. Use an <img> element, or preload the image.
  • The image is inserted by JavaScript, such as a slider or a client-rendered component. The browser cannot fetch it until the script runs. Render the first slide in the HTML.
  • Script-based lazy loading with data-src. Same problem as above, plus the script itself must load first.
  • Low priority. Browsers often start images at low priority until layout reveals they are in the viewport. Adding fetchpriority="high" to the LCP image raises it immediately.

When the image genuinely cannot be in the initial HTML, a preload hint in the head helps the browser start early:

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

If you use responsive images, add imagesrcset and imagesizes to the preload so the browser fetches the right size.

Phase 3: resource load duration

If the download itself is slow, the file is too big or the connection to its host is slow.

  • Size: serve WebP or AVIF, resize to the displayed dimensions, and use srcset so phones get smaller files. A full-width hero rarely needs to be more than about 150–250 KB on mobile. The image SEO guide covers formats and responsive images.
  • Host: images on a separate domain need a new connection (DNS, TCP, TLS) before downloading. Serve the LCP image from the same origin as the page, or add <link rel="preconnect"> to the image host.
  • Contention: if dozens of other resources download at the same time, the LCP image competes for bandwidth. Defer non-critical scripts, and lazy-load images below the fold.
  • Caching: returning visitors should get the image from cache. Long cache lifetimes on static assets help repeat views.

Phase 4: element render delay

The image has downloaded but the browser has not painted it yet. Something is blocking rendering.

  • Render-blocking CSS: large stylesheets in the head must download and parse before anything paints. Inline the critical CSS for above-the-fold content and load the rest without blocking.
  • Render-blocking scripts: synchronous <script> tags in the head block rendering. Use defer or async where possible.
  • Web fonts for text LCP elements: text may stay invisible until the font loads. Use font-display: swap or optional, preload the main font file, and self-host fonts to avoid an extra connection.
  • Client-side rendering: if the page content is built by a JavaScript framework in the browser, nothing meaningful paints until the bundle downloads, parses and runs. Server-side rendering or static generation fixes this at the root; see JavaScript sites and crawlers.
  • A/B testing scripts that hide the page until the experiment loads ("anti-flicker" snippets) add their full load time to LCP. Use them sparingly and with a short timeout.

Lab data versus field data

Lighthouse and the lab section of PageSpeed Insights simulate one load. Search Console's Core Web Vitals report and the field section of PageSpeed Insights use the Chrome User Experience Report: real visits over the previous 28 days. They often disagree, and field data is what counts for Google's assessment.

Two consequences. First, a fix shows up in lab data immediately but takes up to four weeks to fully reflect in field data, since the window is 28 days. Second, field data includes visitors on slow phones and networks, cold caches, and pages reached via redirects from ads or emails. If field LCP is much worse than lab LCP, look at mobile users and at TTFB under real conditions before micro-optimising the front end.

A quick worked example

Take a hypothetical recipe site where mobile field LCP is 3.8 seconds. The LCP element is the main recipe photo. The breakdown on a throttled mobile profile shows TTFB 0.6 s, load delay 1.4 s, load duration 0.9 s, render delay 0.3 s. Load delay is far too large. Inspecting the HTML reveals the photo has loading="lazy" because the CMS applies it to every image, and it is 320 KB as a JPEG.

Removing lazy loading from the first image and adding fetchpriority="high" cuts load delay to about 0.1 s. Serving a 120 KB WebP at the displayed width cuts load duration to about 0.4 s. Lab LCP falls to roughly 1.4 s, and field LCP drops below 2.5 s over the following four weeks. No new server, no framework change: two attributes and a format change, found in fifteen minutes because the diagnosis pointed straight at them.

Checklist

  1. Identify the LCP element on mobile for each key template.
  2. Get the four-phase breakdown and find the outlier.
  3. TTFB high: cache HTML, add a CDN, remove pre-page redirects.
  4. Load delay high: no lazy loading on the LCP image, use img in HTML, fetchpriority="high", preload if needed.
  5. Load duration high: smaller modern formats, responsive sizes, same-origin hosting.
  6. Render delay high: critical CSS, deferred scripts, font-display, server rendering.
  7. Confirm in lab data, then watch field data for four weeks.

Questions

What is a good LCP?

Google's threshold for "good" is 2.5 seconds or less, measured at the 75th percentile of real page loads, separately for mobile and desktop. Between 2.5 and 4 seconds needs improvement; over 4 seconds is poor.

Why is my LCP fine in Lighthouse but poor in Search Console?

Lighthouse runs one simulated load on a fast machine. Search Console uses field data from real Chrome users on real devices and networks over 28 days. Slow phones, slow networks, and pages that are not cached all show up in field data.

Can text be the LCP element?

Yes. A large heading or paragraph block is often the LCP element on article pages. Then web fonts and render-blocking CSS are usually the slow phase.

Does LCP affect rankings?

Core Web Vitals are part of Google's page experience signals. Google describes them as one factor among many, and relevance matters far more. But slow LCP also costs conversions, which is reason enough to fix it.

Keep reading