How to Fix LCP (Largest Contentful Paint) — Step by Step

Learn how to fix LCP (Largest Contentful Paint) step by step. Code examples for image preloading, render-blocking fixes, and server optimizations. Check your LCP free with WebsiteLinter.

10 min read Performance

If you've ever run a PageSpeed Insights test and seen a red or orange score next to Largest Contentful Paint, you already know the frustration. Learning how to fix LCP is one of the highest-leverage performance improvements you can make — it directly affects both your Google search rankings and the experience real visitors have on your site. In this guide, you'll get concrete, code-backed steps to diagnose your LCP element and bring it well under the 2.5-second threshold Google calls "Good."

We'll cover image optimization with preloading, eliminating render-blocking JavaScript and CSS, server-side caching, and CDN delivery — with real code examples at every step.

Quick actions to fix LCP:

  • Convert your hero image to WebP and add <link rel="preload"> in <head>
  • Add fetchpriority="high" to the LCP image element
  • Add defer to non-critical scripts and inline critical above-fold CSS
  • Enable page caching (WP Rocket or WP Super Cache for WordPress)
  • Put your site behind Cloudflare's free CDN tier

Not sure where to start? Run a free WebsiteLinter scan — it automatically identifies LCP issues (and 50+ others) on your site in under 30 seconds.

What Is LCP and Why Does It Matter for Rankings?

Largest Contentful Paint measures how long it takes for the largest visible element above the fold to fully render in the browser viewport. Google defined three performance bands:

Rating LCP Threshold
Good Under 2.5 seconds
Needs Improvement 2.5 – 4 seconds
Poor Above 4 seconds

LCP became an official Google ranking signal as part of the Core Web Vitals update in May 2021. That means a slow LCP doesn't just frustrate visitors — it actively suppresses your page's position in search results. Google uses field data collected from real Chrome users (via the Chrome User Experience Report, or CrUX) to score your pages, so lab scores from tools like PageSpeed Insights are a starting point, not the final word.

The most common LCP elements are:

  • Hero images — the large banner or featured image at the top of a page
  • H1 headlines — large text blocks that dominate the above-fold area
  • Video poster frames — the thumbnail image displayed before a video plays
  • Background images set via CSS — less common but worth checking

Understanding which element is your LCP is the essential first step before applying any fix.

How to Identify Your LCP Element

Before you fix anything, you need to know exactly which element is causing the delay. Here are three reliable methods:

Chrome DevTools — Performance Panel

Open Chrome DevTools (F12), click the Performance tab, then hit the record button and reload your page. Once the recording stops, scroll down in the timeline to the Timings row. You'll see an "LCP" marker — click it to highlight the element in the DOM and see its render timestamp.

PageSpeed Insights

Paste your URL into PageSpeed Insights. In the Diagnostics section, look for "Largest Contentful Paint element" — it will name the exact tag and a snippet of the element's HTML. This is usually the fastest way to identify the culprit without touching DevTools.

Field Data vs. Lab Data

PageSpeed Insights shows two types of data. Lab data (from Lighthouse) simulates a page load in controlled conditions. Field data (from CrUX) reflects real user experiences over the past 28 days. Google's ranking algorithm uses field data, so if your lab score looks good but field data is still Poor, investigate caching layers and third-party script interference.

For a broader view of what else might be hurting your rankings, the WebsiteLinter automated audit guide walks through how to catch performance regressions before they affect your CrUX data.

Fix 1 — Optimize and Preload the LCP Image

For most sites, the LCP element is a hero image. This single fix often produces the biggest score improvement of anything in this guide.

Convert to WebP

WebP images are 25–35% smaller than equivalent JPEGs at the same visual quality. Smaller file = faster download = faster LCP. Use Squoosh to convert manually, or install the Imagify or ShortPixel WordPress plugin to automate conversion site-wide.

Set Explicit Width and Height Attributes

Always include width and height on your <img> tags. The browser uses these to reserve layout space before the image loads, which also prevents Cumulative Layout Shift (CLS) — another Core Web Vital. See our guide on how to fix Cumulative Layout Shift for more on this.

Add a Preload Hint in <head>

A <link rel="preload"> tag tells the browser to fetch the LCP image immediately, before it even parses the rest of the HTML. Without it, the browser typically discovers the image only after parsing the full DOM — often 500ms+ too late.

Use fetchpriority="high"

The fetchpriority attribute (supported in all modern browsers) signals to the browser that this image is the most important resource on the page. Combine it with preload for maximum effect.

Here is a complete code example combining all four techniques:

<!-- In <head>: preload the LCP image with responsive srcset -->
<link
  rel="preload"
  as="image"
  href="/images/hero-800.webp"
  imagesrcset="/images/hero-400.webp 400w,
               /images/hero-800.webp 800w,
               /images/hero-1200.webp 1200w"
  imagesizes="(max-width: 600px) 100vw, 800px"
>

<!-- In <body>: the LCP image itself -->
<img
  src="/images/hero-800.webp"
  srcset="/images/hero-400.webp 400w,
          /images/hero-800.webp 800w,
          /images/hero-1200.webp 1200w"
  sizes="(max-width: 600px) 100vw, 800px"
  alt="Team of web designers working on a custom website project"
  width="800"
  height="450"
  fetchpriority="high"
>

WordPress tip: If your theme sets the hero image via the featured image mechanism, use the wp_get_attachment_image function with 'fetchpriority' => 'high' in the $attr array (available since WordPress 6.3).

Fix 2 — Eliminate Render-Blocking Resources

Even if your LCP image is perfectly optimized, JavaScript and CSS loaded in <head> can hold up the browser's rendering pipeline and delay when your LCP element becomes visible. This is one of the most common causes of LCP scores in the 3–5 second range.

Defer Non-Critical JavaScript

Scripts loaded with a plain <script src="..."> tag pause HTML parsing while they download and execute. Add defer to push execution until after the DOM is parsed. Use async for third-party analytics scripts that don't depend on the DOM.

Inline Critical CSS, Defer the Rest

The browser must download and parse your stylesheet before it can render anything. Extract the CSS rules needed to render above-fold content ("critical CSS") and inline them directly in <head>. Load the full stylesheet non-blockingly using the media="print" trick. Tools like the WP Rocket plugin can automate this extraction for WordPress sites.

<!-- Defer non-critical JavaScript -->
<script src="/js/slider.js" defer></script>
<script src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXX" async></script>

<!-- Inline critical above-fold CSS -->
<style>
  /* Only the styles needed to render above-the-fold content */
  body { margin: 0; font-family: system-ui, sans-serif; }
  .hero { width: 100%; background: #1a1a2e; }
  .hero img { display: block; width: 100%; height: auto; }
  h1 { font-size: clamp(1.75rem, 5vw, 3rem); line-height: 1.2; }
</style>

<!-- Load full stylesheet non-blocking -->
<link
  rel="stylesheet"
  href="/css/main.css"
  media="print"
  onload="this.media='all'"
>
<noscript><link rel="stylesheet" href="/css/main.css"></noscript>

For WordPress-specific render-blocking issues, our guide on how to fix WordPress site speed covers plugin audit techniques and asset optimization workflows in detail.

Fix 3 — Improve Server Response Time (TTFB)

Time to First Byte (TTFB) is the time it takes your server to start sending HTML back to the browser. A TTFB above 600ms significantly inflates your LCP score because nothing can render until that first byte arrives. If your TTFB is slow, even a perfectly optimized image won't save you.

Our dedicated guide to fixing slow TTFB covers this in depth, but here are the key levers:

Enable Page Caching

Page caching stores the fully rendered HTML of your pages on disk so PHP doesn't regenerate them on every visit. For WordPress, WP Super Cache (free) and WP Rocket (paid) are the two most-used options. Properly cached pages typically respond in under 50ms versus 300–800ms for uncached PHP.

Upgrade to PHP 8.2 + OPcache

PHP 8.2 is 2–3x faster than PHP 7.4 on real-world WordPress workloads according to benchmarks from Kinsta and Cloudways. Enable OPcache in your php.ini to cache compiled bytecode — this eliminates repeated PHP compilation overhead on every request.

Add a Persistent Object Cache (Redis)

For sites with complex queries or heavy plugin stacks, a Redis object cache prevents redundant database queries. Here's the wp-config.php configuration alongside a basic nginx FastCGI cache block:

// wp-config.php — Redis object cache
define( 'WP_CACHE', true );
define( 'WP_REDIS_HOST', '127.0.0.1' );
define( 'WP_REDIS_PORT', 6379 );
define( 'WP_REDIS_TIMEOUT', 1 );
define( 'WP_REDIS_READ_TIMEOUT', 1 );
define( 'WP_REDIS_DATABASE', 0 );
# nginx fastcgi_cache block
fastcgi_cache_path /var/cache/nginx levels=1:2
    keys_zone=WORDPRESS:100m inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";

server {
    location ~ \.php$ {
        fastcgi_cache WORDPRESS;
        fastcgi_cache_valid 200 60m;
        fastcgi_cache_bypass $no_cache;
        fastcgi_no_cache $no_cache;
    }
}

Shared hosting note: If you can't modify nginx, focus on WordPress-level caching with WP Rocket and a CDN — together these can cut effective TTFB dramatically without server-level access.

Fix 4 — Deliver Images via a CDN

Even if your server is fast, visitors far from your hosting datacenter experience significant network latency. A Content Delivery Network (CDN) caches your assets on edge nodes worldwide so users always pull from a nearby server.

Cloudflare Free Tier

Cloudflare's free plan is the easiest entry point. Change your domain's nameservers to Cloudflare, enable proxying (the orange cloud), and you immediately get global CDN caching, DDoS protection, and automatic HTTP/2 — no code changes required.

Cloudflare Polish for Automatic WebP

Cloudflare's Polish feature (Pro plan and above) automatically converts images to WebP and strips metadata on the fly. Combined with Mirage (lazy loading at the CDN layer), it can reduce total image payload by 30–40% without touching your WordPress installation.

Preconnect to Your CDN Origin

Add a <link rel="preconnect"> hint for your CDN domain in <head> to establish the TCP/TLS connection early:

<!-- Preconnect to CDN origin -->
<link rel="preconnect" href="https://cdn.yourdomain.com">
<link rel="dns-prefetch" href="https://cdn.yourdomain.com">

<!-- Preconnect to Google Fonts (common render-blocking culprit) -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

For WordPress sites using the media library, plugins like CDN Enabler or WP Offload Media automatically rewrite image URLs to your CDN hostname — this pairs perfectly with the preload technique from Fix 1.

Verify and Monitor Your LCP Score

After applying these fixes, here's a reliable verification process:

Re-Run PageSpeed Insights (Mobile First)

Google's primary index is mobile. Always test your mobile score before desktop. Run the test 3 times and average the LCP values — single-run variance can be ±0.5 seconds due to network conditions. Target a consistent reading below 2.5 seconds.

Check the Core Web Vitals Report in Search Console

Log into Google Search Console → Core Web Vitals report. This shows aggregated field data from real Chrome users visiting your pages. URLs are grouped into "Good", "Needs Improvement", and "Poor" buckets. Prioritize fixing any page with more than 10% of impressions in the Poor bucket.

Understand the 28-Day Field Data Lag

After making your optimizations, the CrUX field data in Search Console takes up to 28 days to fully reflect the changes. Don't panic if rankings don't shift immediately — the improvements are accumulating in the data window. Lab data in PageSpeed Insights will reflect your changes instantly, which confirms your work is taking effect.

Quick-Reference LCP Fix Checklist

Fix Effort Typical LCP Gain Works On
Convert hero image to WebP Low 0.3 – 0.8s All sites
Add <link rel="preload"> + fetchpriority="high" Low 0.4 – 1.2s All sites
Defer non-critical JS Low–Medium 0.2 – 0.6s All sites
Inline critical CSS Medium 0.3 – 0.9s Custom/theme sites
Enable page caching (WP Rocket) Low 0.5 – 1.5s WordPress
Upgrade PHP to 8.2 + OPcache Medium 0.3 – 0.8s WordPress/PHP
Enable Cloudflare CDN Low 0.2 – 1.0s All sites
Redis object cache Medium–High 0.1 – 0.4s WordPress (VPS/dedicated)

The highest-ROI sequence for most WordPress sites: (1) convert LCP image to WebP, (2) add the preload hint with fetchpriority="high", (3) install WP Rocket or WP Super Cache, (4) enable Cloudflare. Those four steps alone routinely move LCP from the 3–5 second range into the sub-2.5 "Good" zone.

For related performance topics, see our guides on fixing slow TTFB and fixing Cumulative Layout Shift — together with this LCP guide, they cover all three Core Web Vitals that directly influence Google rankings. And for a full picture of how LCP fits into your overall site health, the website SEO audit guide shows how to track Core Web Vitals alongside meta tags, structured data, and accessibility issues in a single workflow.

Find every LCP issue automatically. Run your free WebsiteLinter scan now → Get a full Core Web Vitals, SEO, accessibility, and security report — no account required.