Largest Contentful Paint measures how long the biggest visible element above the fold takes to render. The threshold:
Pass: ≤ 2.5s
Needs improvement: 2.5–4.0s
Fail: > 4.0s
For most sites, the LCP element is one of three things — a hero image, a hero text block, or a hero video — and one specific fix moves the score across the threshold. This post is the priority order for diagnosing and fixing LCP.
The Page Speed Grader reports the actual element flagged as the LCP candidate. The report names it directly: <img class="hero-image">, <h1>, or <div class="hero-video-container">.
Three categories of LCP element, each with a different fix:
If the LCP is over 2.5s and the candidate is something else (a footer image, a deeply-nested div), something is genuinely wrong with the page render order. That's a deeper investigation — start by checking that the hero element is in the initial HTML, not injected by JavaScript.
If the LCP candidate is an image, the fastest fix is image optimization.
Convert to WebP or AVIF. WebP is roughly 60-80% smaller than equivalent-quality JPEG. AVIF is even smaller (roughly 80% smaller than JPEG) but has slightly worse browser support — use the <picture> element with both:
Resize to display dimensions. A hero image displayed at 1200×630 should not be a 4000×3000 file. Most CMSs do this automatically (Next.js <Image>, WordPress responsive images); manual implementations often skip it.
Add fetchpriority="high" to the LCP image. This is a 2023 attribute that tells the browser the image is critical and should be fetched before other resources. Browser support is solid as of 2026.
A counterintuitive failure: hero images marked loading="lazy" because the CMS template applies lazy loading globally. The browser delays loading the hero image until the user scrolls — which makes the LCP terrible because the user is looking at the hero from the moment the page loads.
The fix: above-the-fold images need loading="eager" (or no loading attribute, which defaults to eager). Only lazy-load below-the-fold.
Run rg 'loading="lazy"' content/ (or your project's equivalent) to audit. Most lazy-load failures on hero images come from a global template applying it everywhere.
If the LCP candidate is text (an H1, a hero paragraph), the cause is usually a render-blocking font.
The browser blocks rendering of text that uses a web font until the font loads. If the font is 80KB and on a third-party CDN with a slow response, the text takes 2+ seconds to appear — that's your LCP.
Three approaches:
Self-host the font. Google Fonts and other CDN-hosted fonts add a DNS lookup, a TLS handshake, and HTTP latency to every page load. Self-hosted fonts on the same domain skip all three. Tools like fontsource and next/font automate this.
Preload the critical font.<link rel="preload"> for the font used by the LCP element:
Preload only the font weight and style used above the fold. Don't preload all 8 weights of a font family — that wastes bandwidth.
Use font-display: swap for non-critical text. For body text below the fold, swap shows a fallback font immediately and swaps to the web font when it loads. This trades a layout shift (CLS cost) for faster initial render. For LCP specifically, it helps.
If LCP is high and Time to First Byte (TTFB) is also high (over 800ms), no client-side optimization will help much. The browser is waiting on the server.
The grader reports TTFB. If it's over 800ms:
Use a CDN. Cloudflare, Fastly, Vercel Edge, Cloudfront — all measure their value in TTFB reduction. For most sites, putting a CDN in front cuts TTFB by 60-80%.
Static-generate where possible. A page that renders to static HTML has a TTFB measured in milliseconds, not seconds. Server-rendered React pages with heavy data-fetching often have 1-2s TTFB; static-generated pages with the same content have 50ms.
Audit slow database queries. The most common backend cause: a database query in the page render path that takes 500ms+. Add caching, fix the query, or move the data fetch out of the render path.
For sites on Vercel, Netlify, or similar platforms, "static generation" is usually one config change away. For self-hosted sites, the fix is more involved.
A passing LCP doesn't mean a fast page. The user's perception of speed is driven by First Contentful Paint (when anything appears) and by interactivity (when buttons start responding). LCP can pass while FCP is at 3s — that's a page where the user stares at a blank screen for 3 seconds, then sees the hero.
Aim for FCP under 1.8s in addition to LCP under 2.5s. The grader reports both. The same fixes (image optimization, font loading, render-blocking resources) move both metrics.
Once LCP is passing, the next priority is INP (Interaction to Next Paint) — the post-load metric for how snappy the page feels when the user does anything. INP optimization is JavaScript work and usually harder than LCP optimization, but it's the next gate after LCP.