Skip to main content
All fixes

Page speed, redirects, Core Web Vitals

Fix LCP too slow: get Largest Contentful Paint under 2.5s

Largest Contentful Paint above 2.5 seconds fails Core Web Vitals and tanks mobile rankings. Diagnose the LCP element and ship targeted fixes that move the metric.

What's happening

Largest Contentful Paint measures when the largest above-the-fold element — usually a hero image, a video poster, or a big block of text — finishes rendering inside the viewport. Google's Core Web Vitals threshold is 2.5 seconds for a good score, 2.5 to 4 seconds for needs improvement, and anything past 4 seconds is poor. The metric is bucketed at the 75th percentile of real-user traffic in CrUX, so lab numbers from a single Lighthouse run on a fast laptop hide field problems.

The LCP element is whatever the browser paints last out of a candidate set:, inside,, an element with a CSS background-image, and block-level text. Chrome DevTools shows it directly in the Performance panel under Timings, and Lighthouse calls it out in the LCP audit with the actual element selector. Once you know the element, you can split LCP into its four sub-parts: TTFB, resource load delay, resource load duration, and element render delay.

The most common pattern in 2026 is a hero image that the browser doesn't even start fetching until React hydrates and mounts the component. The fix is rarely "make the image smaller" — it's usually "announce the image earlier" via a preload, a static in the initial HTML, or fetchpriority="high".

Why it matters

LCP is one of three Core Web Vitals Google uses as a ranking signal in the page experience update, weighted alongside CLS and INP. Pages that fail Core Web Vitals at the 75th percentile lose mobile SERP visibility, especially against competitors who pass. Search Console's Core Web Vitals report pulls directly from CrUX field data, which means lab fixes don't show up in rankings until real-user metrics catch up.

Beyond ranking, slow LCP correlates with measurable bounce-rate increases. Internal studies from Vodafone, Renault, and others published on web.dev show conversion lifts of 8 to 31 percent after dropping LCP under 2.5s. Mobile users on flaky 3G/4G in particular abandon if the hero takes more than three seconds to appear.

Common causes

  • Hero image is fetched only after JavaScript hydrates, instead of being in the initial HTML.
  • Render-blocking CSS or JavaScript pushes the LCP element's paint past 2.5s.
  • Server TTFB is already 800ms+ before the document even starts streaming.
  • The LCP image is served as a 2MB JPEG instead of an AVIF or WebP at the actual rendered size.
  • fetchpriority="high" is missing on the hero image, so the browser deprioritizes it behind fonts and analytics scripts.
  • A large client-side JS bundle blocks the main thread during the critical render path.
  • No preconnect hints to the image CDN, so connection setup adds 100-300ms.

Detect this on your site

Run a quick scan with the Speed Test. The tool surfaces this exact issue with the records and context needed to apply the fix below.

Open Speed Test

How to fix it

  1. 1

    Identify the actual LCP element

    Run the page in Chrome DevTools Performance panel with Web Vitals overlay enabled, or open Lighthouse and look at the "Largest Contentful Paint element" diagnostic. The selector tells you exactly which DOM node is the bottleneck — don't optimize blindly.

  2. 2

    Move the LCP image into the initial HTML

    If the LCP element renders inside a client component, server-render it instead. In Next.js App Router, use a Server Component with next/image so the tag is in the streamed HTML. The browser's preload scanner will discover it before any JS runs.

  3. 3

    Add fetchpriority="high" to the LCP image

    Browsers default to low priority for images discovered late. Setting fetchpriority="high" on the hero tells Chrome and Edge to fetch it ahead of fonts and non-critical scripts. next/image exposes this via the priority prop.

  4. 4

    Preload critical hero assets

    Add in the document head, plus for the image origin. Don't preload more than 2-3 things — over-preloading starves the rest of the critical path.

  5. 5

    Serve the image in AVIF or WebP at exact rendered size

    A 1920x1080 hero rendered at 800x450 on mobile should ship a 800x450 AVIF, not the full-resolution master. Use srcset with a CDN like Cloudflare Images, Vercel's Image Optimization, or imgix to generate responsive variants on the fly.

  6. 6

    Eliminate render-blocking CSS and JS

    In the Lighthouse "Eliminate render-blocking resources" opportunity, inline critical CSS and defer the rest. Move third-party scripts (analytics, chat widgets, A/B testing) to or the Next.js Script component with strategy="lazyOnload".

  7. 7

    Validate with field data, not just Lighthouse

    After deploying, watch the 75th-percentile LCP in PageSpeed Insights' "Origin Summary" section, which pulls from CrUX. Lab improvements take 28 days to fully reflect in field data. The web-vitals.js library lets you ship LCP measurements to your own analytics for faster feedback.

Example

<head>
  <link rel="preconnect" href="https://cdn.example.com" crossorigin>
  <link rel="preload" as="image" href="https://cdn.example.com/hero.avif"
        imagesrcset="https://cdn.example.com/hero-800.avif 800w,
                     https://cdn.example.com/hero-1600.avif 1600w"
        imagesizes="100vw" fetchpriority="high">
</head>
<body>
  <img src="https://cdn.example.com/hero.avif"
       srcset="https://cdn.example.com/hero-800.avif 800w,
               https://cdn.example.com/hero-1600.avif 1600w"
       sizes="100vw" alt="" fetchpriority="high" decoding="async">
</body>

Preload + responsive srcset + fetchpriority for the LCP image.

Frequently asked

PageSpeed Insights aggregates lab and field data. For real-device debugging use Chrome DevTools' Performance panel with CPU and network throttling or remote-debug a phone via USB. The web-vitals.js library shipped to production gives you per-user LCP straight from RUM.

Lighthouse runs on a simulated Moto G4 with throttled 4G in a single cold load. CrUX aggregates millions of real users on slower devices flaky networks and warm caches. Trust field data — it's what Google ranks on.

fetchpriority is supported in Safari 17.2+ Chrome 101+ and Firefox 119+. On older Safari it's ignored without breaking so it's safe to ship today as a progressive enhancement.

Related fixes