# Largest Contentful Paint (LCP): what it is and how to fix it

**Audit ID:** `largest-contentful-paint` · **Category:** Performance · **Core Web Vital**

LCP is one of Google's three Core Web Vitals. It measures how quickly the biggest visible element on your page renders, and it's a direct ranking signal.

## TL;DR

- **What:** Time until the largest visible element finishes rendering.
- **Target:** Under 2.5 seconds (the official "Good" threshold).
- **Top three fixes:** preload the LCP image, remove its `loading="lazy"`, eliminate render-blocking CSS and JS.
- **Where to start:** identify the LCP element from your Lighthouse report, it tells you exactly which DOM node is the bottleneck.

## What LCP measures

Largest Contentful Paint reports the moment the single largest visible element finishes rendering inside the viewport. "Largest" is measured by rendered area on screen. Common LCP elements include hero images, the main heading on a marketing page, a video poster frame, or a large block of text.

LCP measures user-perceived load time. Even if your DOM is interactive, if the user can't see meaningful content yet, the page feels slow.

## What's a good LCP score?

| Range | Verdict |
|---|---|
| ≤ 2.5 s | Good |
| 2.5–4 s | Needs improvement |
| > 4 s | Poor |

Google applies these thresholds to the 75th-percentile of real-user data, not lab data.

## Why LCP is hard to fix

LCP failures are rarely caused by one slow thing. The metric represents a chain: DNS lookup → server response → HTML download → CSS parse → render-blocking JS → discover the LCP resource → fetch it → decode and paint it. A weak link anywhere in that chain delays LCP.

## Five concrete fixes

### 1. Identify the LCP element

Open the Lighthouse report and find the "Largest Contentful Paint element" diagnostic. It names the specific DOM node responsible.

```html
<!-- Lighthouse tells you something like this: -->
<img class="hero" src="/hero-banner.jpg" alt="Product hero" />
```

### 2. Preload the LCP resource

```html
<head>
  <link rel="preload" as="image" href="/hero-banner.jpg" fetchpriority="high" />
</head>
```

For responsive images, use `imagesrcset` and `imagesizes` attributes on the preload tag.

### 3. Never lazy-load the LCP element

```html
<!-- WRONG: above-the-fold image with lazy-loading -->
<img src="/hero.jpg" loading="lazy" />

<!-- RIGHT: explicit eager fetch with high priority -->
<img src="/hero.jpg" loading="eager" fetchpriority="high" />
```

### 4. Eliminate render-blocking CSS and JavaScript

- Inline critical CSS in `<head>`; defer the rest with `<link rel="preload" as="style" onload="this.rel='stylesheet'">`
- Move non-essential `<script>` tags to the bottom of `<body>` or add `defer` / `async`

### 5. Reduce server response time (TTFB)

TTFB is the floor of LCP. If your server takes 800 ms to send the first byte, LCP cannot be faster than 800 ms.

- Put a CDN in front of origin (Cloudflare, Fastly, Vercel Edge)
- Enable HTTP/2 or HTTP/3
- Cache rendered HTML at the edge
- Move slow operations off the critical request path

## Verification

1. Re-run Lighthouse. Confirm LCP < 2.5 s on both strategies.
2. Wait 28 days for Chrome User Experience Report (CrUX) to reflect real-user data.
3. Don't optimize past the threshold, spend budget on the next-worst audit.

## Related audits

- [Cumulative Layout Shift (CLS)](/audits/cumulative-layout-shift), visual stability
- [Total Blocking Time (TBT)](/audits/total-blocking-time), main-thread blocking
- [Render-blocking resources](/audits/render-blocking-resources), CSS/JS that delays first paint
- [Reduce unused JavaScript](/audits/reduce-unused-javascript), wasted bytes

---

Audit your URL at https://lighthouse-md.com, paste a URL, get scores plus a CLAUDE.md fix plan for Claude Code.
