Largest Contentful Paint Optimization: A Friendly, Authoritative Guide

LCP optimization
Core Web Vitals
web performance

If you’ve ever wondered why a page feels sluggish even though the HTML arrived quickly, the answer often lies in Largest Contentful Paint (LCP). LCP measures the moment the biggest piece of content—usually a hero image, a heading, or a video poster—becomes visible inside the viewport. Google treats this as a Core Web Vital, aiming for a score of 2.5 seconds or less on at least 75 % of visits. When LCP is fast, users perceive the page as loading swiftly, bounce rates drop, and search rankings can improve.

Below is a complete, step‑by‑step approach to improving LCP. We’ll start with how to measure it, break the metric into its four underlying phases, and then outline concrete actions for each phase. All recommendations are practical, tested across real‑world sites, and avoid the fluff you’ll find elsewhere.

How to Measure LCP Accurately

Before you optimize, you need a reliable baseline. Lab tools like Lighthouse or PageSpeed Insights give you a quick snapshot, but they don’t always reflect what real visitors experience. For true insight, pair lab data with field data from the Chrome User Experience Report (CrUX) or a Real User Monitoring (RUM) service.

  • PageSpeed Insights shows both CrUX (field) and Lighthouse (lab) numbers side‑by‑side. Focus first on the field data; if it’s missing, the origin‑level CrUX numbers are a decent fallback.
  • Chrome DevTools → Performance tab → record a reload, then inspect the LCP marker. Hovering over it reveals the exact element and the timing breakdown.
  • WebPageTest lets you test from various locations and connection speeds, useful for spotting geographic bottlenecks.
  • RUM tools (DebugBear, SpeedCurve, CoreDash, etc.) continuously collect LCP from real users and can alert you when the 75th‑percentile crosses the 2.5. Performance Observer API – If you want to instrument your own site, a few lines of JavaScript can capture LCP and its sub‑parts for internal analytics.

Once you have a baseline, you’ll know whether you’re already under the 2.5 second target or where the biggest gaps lie.

Breaking LCP Into Four Phases

Every LCP timestamp can be split into four sequential, non‑overlapping components. Understanding which phase consumes the most time tells you where to focus effort.

PhaseWhat it MeasuresTypical Share of a 2.5 s LCP
Time to First Byte (TTFB)Server‑side delay: DNS, TCP/TLS, request processing, and first byte of HTML.~40 %
Resource Load DelayGap between TTFB and the browser’s first request for the LCP resource (image, font, video).< 10 %
Resource Load DurationTime to actually download the LCP resource.~40 %
Element Render DelayTime from when the resource finishes downloading to when the element is painted on screen.< 10 %

If any phase is inflated, the overall LCP suffers. Optimizing one phase can sometimes shift time to another (e.g., shrinking an image may move delay from download to rendering), so you’ll want to address all four, prioritizing the biggest offenders.

Below we walk through each phase and give proven tactics.

1. Reduce Time to First Byte (TTFB)

TTFB is the foundation. No matter how fast you download images, a slow server response will keep LCP high.

Use a CDN for HTML

A Content Delivery Network caches your HTML at edge locations. When a user requests a page, the CDN serves it from the nearest point of presence, cutting network latency dramatically. For static sites, a CDN can push TTFB into the low‑double‑digits. For dynamic sites, look for CDNs that offer edge compute (Cloudflare Workers, Vercel Edge Functions, Fastly Compute@Edge) so you can run server‑side logic close to the user.

Enable Server‑Side Caching

If your pages are largely static, cache the full HTML response. Tools like Varnish, Nginx fastcgi_cache, or a managed host’s built‑in cache can serve stale copies while regenerating in the background. For dynamic content, a multi‑layer cache (in‑memory → Redis → disk) reduces the chance of a cache miss.

Leverage Early Hints (HTTP 103)

Early Hints let the server send preload directives before the full HTML is ready. The browser can start fetching critical CSS, fonts, or the LCP image while waiting for the response. Many CDNs (Cloudflare, Fastly) support this natively; if your origin doesn’t generate hints, the CDN can learn from past responses and inject them automatically.

Optimize Backend Work

  • Profile your application to spot expensive database queries or heavy templating.
  • Use the latest stable PHP version (or Node, Python, etc.) – each minor release often brings ~5‑10 % performance gains.
  • Keep the number of active plugins low; each adds overhead to the request pipeline.
  • Consider moving heavy rendering to a static site generator or using server‑side rendering (SSR) frameworks like Next.js, Nuxt, or Remix, which send fully rendered HTML on the first request.

Prioritize Third‑Party Connections

External scripts (analytics, ads, widgets) can delay the start of HTML parsing. Add <link rel="preconnect" href="https://third‑party.com"> or dns-prefetch for domains you know you’ll need. This lets the browser set up TLS/TCP handshakes early, shaving tens of milliseconds off TTFB.

2. Eliminate Resource Load Delay

Even if the server replies instantly, the browser might not know to fetch the LCP resource until later. This delay happens when the resource isn’t discoverable in the initial HTML or when it’s given low priority.

Make the LCP Resource Discoverable in HTML

The browser’s preload scanner parses raw HTML to find URLs for images, scripts, fonts, etc. If your LCP image is added via JavaScript or appears only as a CSS background‑image, the scanner misses it, causing a delay of hundreds of milliseconds.

  • For <img> elements: Ensure the src (or srcset) attribute is present in the HTML sent from the server.
  • For CSS background images: Add a <link rel="preload" as="image" href="…" fetchpriority="high"> tag in the <head>.
  • For web fonts: Preload the font file with as="font" and the appropriate crossorigin attribute if needed.
  • For video poster images: Same as above – preload the poster.

Assign High Fetch Priority

By default, browsers treat images as low‑priority resources. The fetchpriority attribute tells the browser to treat a specific resource as critical.

<img src="/hero.webp" alt="Hero" fetchpriority="high">
<link rel="preload" as="image" href="/hero.webp" fetchpriority="high">

Use this only on the true LCP candidate (usually one image per page). Over‑prioritizing many resources defeats the purpose and can cause bandwidth contention.

Avoid Lazy Loading Above‑the‑Fold Images

Lazy loading is excellent for images below the fold, but applying it to the LCP element adds an artificial wait. Remove loading="lazy" from any image that could be the LCP, or explicitly set loading="eager" (the default) for those assets.

Prefer Server‑Side Rendering or Static Generation

If your LCP element depends on client‑side JavaScript (React, Vue, Svelte), the browser must download, parse, and execute that bundle before it can discover the image. Switching to SSR or static site generation (SSG) puts the image URL directly in the HTML, eliminating this delay.

3. Shrink Resource Load Duration

Once the browser knows to fetch the LCP resource, the download time depends mainly on file size and network conditions. You can’t control the user’s connection, but you can make the resource as small as possible.

Adopt Modern Image Formats

Use the <picture> element to serve AVIF/WebP with a JPEG fallback, or rely on an image CDN that negotiates format based on the Accept header.

  • AVIF offers ~50 % smaller files than JPEG at comparable quality and enjoys broad support in Chrome, Firefox, Safari (≥16.1), and Edge.
  • WebP is a solid fallback, typically 25‑35 % smaller than JPEG.
<picture>
  <source srcset="/hero.avif" type="image/avif">
  <source srcset="/hero.webp" type="image/webp">
  <img src="/hero.jpg" alt="Hero" width="1200" height="630"
       fetchpriority="high" decoding="async">
</picture>

Responsive Images with srcset and sizes

Serve different resolutions based on the user’s screen width and device pixel ratio. This prevents sending a 4000‑pixel wide image to a phone.

<img src="/hero-800w.webp"
     srcset="/hero-400w.webp 400w,
             hero-800w.webp 800w,
             hero-1200w.webp 1200w"
     sizes="(max-width: 600px) 400px,
            (max-width: 1024px) 800px,
            1200px"
     alt="Hero"
     fetchpriority="high">

Compress and Optimize

  • Run images through tools like Squoosh, ImageOptim, or CI pipelines (sharp, imagemin) to strip unnecessary metadata and apply optimal compression levels.
  • For JPEGs, enable progressive encoding; for PNGs, use lossless compression (e.g., Oxipng).
  • Remove unused color profiles.

Leverage a CDN for Image Delivery

An image‑specific CDN (Cloudflare Images, Imgix, Cloudinary) can automatically resize, compress, and convert formats on the fly, ensuring each user gets the smallest possible file.

Cache‑friendly version. Set aggressive Cache‑Control headers (e.g., public, max‑age=31536000, immutable) so repeat visits hit the browser cache.

Consider Inlining Tiny Assets

If the LCP resource is under a few kilobytes (e.g., a small SVG icon or a critical web font subset), inlining it as a data URL eliminates the network request altogether. Use this sparingly; large inlined assets bloat the HTML and hurt caching.

4. Minimize Element Render Delay

Even after the LCP resource has arrived, the browser may stall before painting it. Render delay is usually caused by the main thread being blocked by CSS or JavaScript.

Inline Critical CSS

The browser won’t paint anything until it has parsed all CSS in the <head>. Extract the CSS needed to render the above‑the‑fold portion (the “critical CSS”) and place it directly inside a <style> tag. Load the rest of the stylesheet asynchronously with a preload/onload pattern:

<head>
  <style>
    /* critical CSS for hero, nav, heading */
    .hero { … }
    h1 { … }
  </style>
  <link rel="preload" href="/styles.css" as="style"
        onload="this.onload=null;this.rel='stylesheet'">
  <noscript><link rel="stylesheet" href="/styles.css"></noscript>
</head>

Tools like critters (webpack/Vite) or critical (standalone) can automate this extraction during your build.

Defer or Async Non‑Critical JavaScript

<script> tags without async or defer block HTML parsing. Move non‑essential scripts to the bottom of the body or add defer/async.

<script src="/app.js" defer></script>
<script src="/analytics.js" async></script>

If a script must run before the LCP element appears (e.g., a layout‑critical inline script), keep it tiny and consider inlining it.

Optimize Web Font Loading

Custom fonts can cause a Flash of Invisible Text (FOIT), delaying text rendering. Use font-display: swap (or optional if you prefer a fallback) to show text immediately with a system font, then swap in the custom font once it loads.

Preload the font file to reduce the swap delay:

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

Consider self‑hosting fonts and subsetting them to include only the characters you actually need.

Break Up Long Tasks

Long-running JavaScript keeps the main thread busy, postponing paint. Use the Chrome DevTools “Performance” panel to spot tasks > 50 ms. Strategies:

  • Split large bundles with code‑splitting (dynamic import()).
  • Offload work to Web Workers when possible.
  • RequestIdleCallback or setTimeout to yield to the browser.

Avoid Render‑Blocking Imports

If you load a CSS file via @import inside another stylesheet, the browser waits for the imported file before proceeding. Prefer <link> tags in the HTML and combine or concatenate stylesheets where feasible.

Putting It All Together: A Practical Checklist

PhaseActionWhy it Helps
TTFBServe HTML from a CDN edge; enable full‑page caching; use HTTP/103 Early Hints; optimize backend code; preconnect to critical third‑party origins.Reduces the time before the browser can even start downloading resources.
Resource Load DelayEnsure LCP <img> src/srcset is in the HTML; preload background images, fonts, video posters; add fetchpriority="high"; remove loading="lazy" from above‑the‑fold images; prefer SSR/SSG for JS‑driven LCP.Makes the browser discover and prioritize the LCP resource instantly.
Resource Load DurationDeliver LCP image in AVIF/WebP with proper srcset/sizes; compress aggressively; serve via an image CDN; leverage aggressive caching; inline tiny critical assets.Shrinks the download time.
Element Render DelayInline critical CSS; defer/async non‑critical JS; use font-display: swap + font preload; break up long JavaScript tasks; avoid @import in CSS.Lets the browser paint as soon as the resource is ready.

After implementing these steps, re‑measure with both lab and field tools. Aim for a 75th‑percentile LCP under 2.5 seconds on mobile and desktop. If you’re still above the target, revisit the breakdown to see which phase remains the bottleneck and apply deeper fixes there.

Why This Approach Works

LCP optimization isn’t about a single magic trick; it’s about smoothing the entire loading chain. By attacking each of the four phases with focused, evidence‑based tactics, you remove the most common sources of delay:

  • Server latency is cut with CDN, caching, and early hints.
  • Discovery delays vanish when the LCP resource is visible to the preload scanner and given high priority.
  • Download time drops thanks to modern formats, responsive sizing, and compression.
  • Render delays disappear when the main thread is free to paint as soon as the resource arrives.

Sites that follow this checklist consistently move from “Poor” or “Needs Improvement” to “Good” LCP scores, which translates into better user engagement, lower bounce rates, and a stronger position in search results.


Final Thoughts

Start with a solid measurement baseline, identify which LCP phase is costing you the most time, and apply the corresponding optimizations. Remember that the goal isn’t just to hit a number—it’s to deliver a perceivably fast experience for your real visitors, wherever they are and whatever device they use. When the largest piece of content appears quickly, users feel the site is responsive, trustworthy, and worth staying on. That’s the true payoff of LCP optimization. Happy speeding!

Share this post:
Largest Contentful Paint Optimization: A Friendly, Authoritative Guide