# How to improve Largest Contentful Paint (LCP)

> LCP measures how fast the largest visible element loads, and it counts for 25% of your PageSpeed score. Here's what actually moves the number on WordPress, with a list of second-order fixes at the end.

Published: 2021-11-04T05:09:03.000Z
Updated: 2026-04-24T10:00:00.000Z
Author: Shameem Reza
Category: WordPress
Canonical: https://shameemreza.com/how-to-improve-largest-contentful-paint-lcp/

---

import Tldr from '../../components/Tldr.astro';

Largest Contentful Paint is the Core Web Vitals metric that measures how long it takes for the largest visible element in the viewport to render. Until the LCP element paints, the page looks half-broken. In practice, it's usually the hero image, a large heading, or a video poster frame.

Google wants the LCP under 2.5 seconds for a "good" rating. LCP is weighted at 25% of the PageSpeed performance score, and it feeds directly into the Core Web Vitals signal for Search. If one number moves your speed score and your SEO at the same time, it's this one.

![Shameem website speed report](/uploads/shameem-website-speed-1024x451.png)

<Tldr>
  Fix the host, fix the LCP image. Those two changes move the number more than anything else. On WordPress, the host decides your server response time, which is the floor for every Core Web Vital. The LCP image decides your ceiling, because it's usually the largest file that has to download before the page feels ready. Everything else (minification, unused CSS, service workers, code-splitting) is second-order. It compounds on top of a fast host and an optimized hero image, not in place of them.
</Tldr>

## What causes a slow LCP

Before you fix anything, run the page through PageSpeed Insights or the Core Web Vitals report in Search Console to see what your actual LCP is. From there, the usual suspects are:

- **Slow server response time.** The browser can't render anything until the HTML arrives. If TTFB is bad, LCP can't be good.
- **Render-blocking JavaScript and CSS.** Every synchronous script or external stylesheet in the `<head>` delays first paint. The more plugins and the heavier the theme, the worse this gets.
- **Large hero assets.** A 3 MB PNG as the LCP element is the most common cause I see on WordPress sites. Resize, compress, and serve it at the dimensions you're actually using.
- **Client-side rendering.** If your hero is rendered by JavaScript after hydration, the browser has to download and parse JS before anything paints. Server-rendered HTML almost always gives you a better LCP.

## The two fixes that actually move the number

### Move to a host that prioritises performance

LCP is a measure of how fast content arrives. Everything after TTFB compounds on top of TTFB. If your host is slow, you can optimise the page for a week and barely move the number.

If you're on WordPress, I work at Automattic, so my go-tos are [WordPress.com](https://wordpress.com) for most sites and [Pressable](https://pressable.com) when you need SFTP, SSH, staging, or you're managing client sites at scale. Both run on WP Cloud with global caching baked in. Shared hosting is almost always where poor LCP starts.

### Optimize the LCP image

Open the PageSpeed Insights report and look at the "Largest Contentful Paint element" line. That's the one file you need to fix first.

- Serve it in WebP or AVIF if you can. Both cut file size by 30 to 60% compared to PNG at the same quality.
- Resize it to the dimensions actually displayed. A hero image rendered at 1200 pixels wide doesn't need a 4000-pixel-wide source.
- Add `fetchpriority="high"` on the `<img>` tag so the browser prioritises it over other resources.
- If it's a custom field image in a theme template, preload it with `<link rel="preload" as="image" href="...">` in the `<head>`.

The combination of a correctly-sized WebP plus `fetchpriority="high"` is usually the single biggest LCP improvement on a content-heavy WordPress site.

## Second-order fixes

These matter, but they move the number less than the two above. Do them after the host and the hero image are sorted.

### Use a CDN

A [CDN](https://en.wikipedia.org/wiki/Content_delivery_network) caches your static assets at edge locations close to your visitors. For a visitor in Madrid, a file served from Frankfurt is dramatically faster than the same file served from your origin in Virginia.

I use [BunnyCDN](https://bunny.net) for most projects. It's cheap and fast. Cloudflare's free tier works too if you want a zero-cost option. Both WordPress.com and Pressable include a CDN by default, so you usually don't need to configure one separately if you're on WP Cloud.

### Cache aggressively

If your host doesn't already cache HTML at the edge, use a caching plugin like WP Rocket. If it does (WP Cloud, Kinsta, Cloudways), don't add a caching plugin on top, you'll fight with the host's cache and create weird invalidation bugs.

### Service workers for returning visitors

A service worker can serve the cached HTML instantly on a repeat visit while it revalidates in the background. LCP drops to near-zero on second page views. This is a real win for content sites, but it's complex to set up correctly, and it's only worth the effort after the host and hero image are fixed.

### Reduce render-blocking JS and CSS

Open DevTools, go to the Coverage tab, and look at how much of your CSS and JS is unused on the first page view. For most WordPress themes, it's 60 to 80%. You don't need to get to zero, you just need the critical path to be fast.

The two biggest wins here are:

- `defer` or `async` every script that isn't needed before first paint.
- Inline the critical CSS for the above-the-fold content and load the rest asynchronously.

Plugins like WP Rocket, FlyingPress, and Perfmatters automate both of these. Do them after you've squeezed the image wins, not before.

### Compress everything else

Enable Brotli or gzip on the server for HTML, CSS, and JS. Minify JS and CSS at build time. These are one-time changes that compound over every request but don't solve anything on their own.

## The priority order, one more time

If you remember one thing from this post:

1. Fast host.
2. Optimized LCP image with `fetchpriority="high"` and preload.
3. Everything else.

A slow host with a 3 MB PNG as the LCP element will still score poorly no matter how aggressively you minify your JavaScript. Get the first two right before you spend an afternoon on the third.
