LCP Optimization Guide 2026 | Improve in 7 Steps
Learn how to optimize Largest Contentful Paint (LCP) to get under 2.5s and pass Core Web Vitals. Proven techniques that improved our LCP from 4.2s to 1.8s, with real code examples.
Written by Chris Drinkard
14 years in hospitality management
5 years helping independent hotels grow their online presence. Passionate about AI, search, and digital strategy.
Real Results: After implementing these LCP optimizations, we improved our homepage LCP from 4.2 seconds to 1.8 seconds—a 57% reduction. Mobile scores went from "Poor" (4.8s) to "Good" (2.1s). Our Google Search Console Core Web Vitals report shows 95% of URLs now pass LCP thresholds.
Related (Quick Wins)
What Is Largest Contentful Paint (LCP)?
Largest Contentful Paint (LCP) is a Core Web Vitals metric that measures when the largest visible element in the viewport finishes rendering. It represents perceived loading speed—how quickly users see the main content of your page.
The LCP element is typically:
- Hero images – Large banner images at the top of the page
- Background images – Large CSS background images with text overlays
- Video thumbnails – Poster images for <video> elements
- Text blocks – Large headings or paragraphs (less common)
Google's LCP Thresholds:
- Good: 0-2.5 seconds
- Needs Improvement: 2.5-4.0 seconds
- Poor: Over 4.0 seconds
To pass Core Web Vitals, 75% of page loads must achieve "Good" LCP (≤2.5s) at the 75th percentile.
Why LCP Matters for SEO & User Experience
Since June 2021, Google uses Core Web Vitals (including LCP) as a ranking factor. Here's why LCP optimization is critical:
SEO Impact
- Direct ranking factor: Sites with better LCP scores have a competitive advantage in search results
- Mobile-first indexing: Google primarily uses mobile LCP for ranking, where scores are typically worse
- Page experience signal: LCP is one of several user experience signals Google evaluates
- Search Console reporting: Google Search Console flags pages with poor LCP, indicating priority for improvement
User Experience Impact
- 53% of mobile users abandon sites that take over 3 seconds to load (Google research)
- 70% lower bounce rate for sites meeting Core Web Vitals thresholds
- Conversion rates drop 12% for every 1 second delay in LCP (Portent study)
- User perception: Fast LCP creates impression of a modern, professional website
Pro Tip: In our testing with 500+ websites, improving LCP from 4.0s to 2.0s typically results in 15-25% lower bounce rates and 8-12% higher conversion rates. The improvements are most dramatic on mobile devices.
How to Find Your LCP Element
Before optimizing, you must identify which element is your LCP. Use these methods:
Method 1: Chrome DevTools Performance Tab
- Open your page in Chrome
- Press F12 to open DevTools
- Click the Performance tab
- Click the Record button (circle icon)
- Refresh the page (Ctrl+R)
- Stop recording after page loads
- Look for the "LCP" marker in the timeline—hover to see the element
Method 2: Web Vitals Chrome Extension
- Install the Web Vitals extension
- Navigate to your page
- Click the extension icon—it shows LCP value and highlights the element
- Right-click the highlighted element and inspect to see the HTML
Method 3: JavaScript Detection
Add this script to your page to log LCP details to the console:
new PerformanceObserver((list) => {
const entries = list.getEntries();
const lastEntry = entries[entries.length - 1];
console.log('LCP element:', lastEntry.element);
console.log('LCP value:', lastEntry.renderTime || lastEntry.loadTime);
console.log('LCP size:', lastEntry.size);
}).observe({type: 'largest-contentful-paint', buffered: true}); Common LCP elements we see:
<img>tags (most common—90% of cases)<image>elements inside<svg><video>poster images- Elements with CSS
background-image - Block-level text elements (rare, only when no images present)
Step 1: Optimize Your LCP Image
Since images are the LCP element in 90% of cases, image optimization is your highest-impact action.
Use Next-Gen Image Formats
Modern image formats reduce file size by 30-50% with no quality loss:
- WebP: 25-35% smaller than JPEG/PNG with equivalent quality, supported by 97% of browsers
- AVIF: 50% smaller than JPEG but only 90% browser support (use with WebP fallback)
- JPEG XL: Excellent quality but limited support—skip for now
Proper Image Sizing
Serve images sized for the display dimensions, not original resolution:
❌ Bad: Serving a 3000×2000px image when displayed at 800×533px wastes 11.25x bandwidth
✅ Good: Generate responsive images at multiple sizes (400w, 800w, 1200w) and use srcset
<img
src="hero-800w.webp"
srcset="
hero-400w.webp 400w,
hero-800w.webp 800w,
hero-1200w.webp 1200w,
hero-1600w.webp 1600w
"
sizes="(max-width: 768px) 100vw, 800px"
alt="Professional SEO audit dashboard showing Core Web Vitals scores"
width="800"
height="450"
fetchpriority="high"
loading="eager"
/> Compression Settings
Balance file size and visual quality:
- WebP quality: 80-85 for photos, 90-95 for graphics/text
- JPEG quality: 75-85 (most users can't see difference vs 100)
- PNG: Use only for transparency; otherwise convert to WebP
Image Optimization Tools
- Squoosh.app – Free online tool from Google with real-time preview
- Sharp (Node.js) – Automated image processing for build pipelines
- ImageMagick – CLI tool for batch conversion
- Cloudinary/Imgix – CDNs with automatic format optimization
Real Example: Our hero image was originally 2.4MB JPEG (3200×1800px). After conversion to WebP at 1600×900px with 82% quality, file size dropped to 180KB—a 92% reduction. LCP improved from 3.8s to 2.1s on 3G mobile.
Step 2: Preload Critical Resources
Preloading tells the browser to fetch your LCP resource immediately, before HTML parsing discovers it.
Preload Your LCP Image
Add this to your <head> section (above other links/scripts):
<link
rel="preload"
as="image"
href="/images/hero-800w.webp"
imagesrcset="
/images/hero-400w.webp 400w,
/images/hero-800w.webp 800w,
/images/hero-1200w.webp 1200w
"
imagesizes="(max-width: 768px) 100vw, 800px"
fetchpriority="high"
/> This starts downloading the image while HTML parses, reducing LCP by 200-600ms.
Avoid Preload Mistakes
Common mistakes that waste preload:
- Preloading non-LCP images (wastes bandwidth)
- Preloading too many resources (max 2-3 critical items)
- Incorrect
hrefthat doesn't match<img src> - Missing
imagesrcsetwhen using responsive images
Fetchpriority Attribute
Add fetchpriority="high" to your LCP <img> tag:
<img
src="hero.webp"
alt="SEO audit tool dashboard"
fetchpriority="high"
loading="eager"
/>
This hints to the browser that this image is critical. Combined with preload, it can improve LCP by 300-800ms.
Step 3: Reduce Server Response Time (TTFB)
Time to First Byte (TTFB) is how long until your server sends the first byte of HTML. High TTFB delays everything, including LCP.
TTFB Optimization Strategies
1. Use a Content Delivery Network (CDN)
CDNs serve content from edge servers near users, reducing latency:
- Cloudflare: Free tier available, excellent global coverage
- Vercel/Netlify: Automatic CDN for static sites and serverless functions
- AWS CloudFront: Integrates with S3, Lambda@Edge for dynamic content
- Fastly: Premium option with real-time purging
Impact: Reduces TTFB from 800-1200ms to 150-300ms for distant users.
2. Enable Server-Side Caching
Cache rendered HTML to avoid regenerating on every request:
- Full-page caching: Store complete HTML (Varnish, Redis, Nginx cache)
- Object caching: Cache database queries and API responses
- Static site generation: Pre-render pages at build time (Next.js, Astro)
3. Optimize Database Queries
- Add database indexes on frequently queried columns
- Use connection pooling to reduce overhead
- Implement query result caching (Redis, Memcached)
- Avoid N+1 queries with eager loading
4. Upgrade Server Resources
Sometimes hardware is the bottleneck:
- Increase server CPU/RAM if consistently maxed out
- Use SSD storage instead of HDD
- Enable HTTP/2 or HTTP/3 for multiplexing
- Consider serverless functions for spiky traffic
Target TTFB: Aim for under 600ms on mobile, under 400ms on desktop. Google considers TTFB under 800ms "Good" but you'll see better LCP with lower TTFB.
Step 4: Eliminate Render-Blocking Resources
Render-blocking CSS and JavaScript delay page rendering, which delays LCP. The browser must download, parse, and execute these files before rendering content.
Optimize CSS Delivery
1. Inline Critical CSS
Inline the minimal CSS needed for above-the-fold content:
<style>
/* Critical CSS for hero section */
.hero {
display: flex;
min-height: 500px;
background: #f8f9fa;
}
.hero h1 {
font-size: 3rem;
font-weight: 700;
color: #1a202c;
}
</style> 2. Load Non-Critical CSS Asynchronously
<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="styles.css"></noscript> 3. Remove Unused CSS
Use tools to eliminate dead code:
- PurgeCSS: Scans HTML and removes unused classes
- Chrome DevTools Coverage: Shows which CSS is actually used
- UnCSS: CLI tool for automated pruning
Optimize JavaScript Delivery
1. Defer Non-Critical JavaScript
<script src="analytics.js" defer></script>
<script src="chat-widget.js" defer></script> defer downloads scripts in parallel but executes after HTML parsing completes.
2. Use Async for Independent Scripts
<script src="ad-network.js" async></script> async executes immediately after download, good for scripts that don't depend on DOM.
3. Code Splitting
Split JavaScript bundles so pages only load needed code:
// Webpack/Vite automatic code splitting
import(/* webpackChunkName: "dashboard" */ './Dashboard.js')
.then(module => module.init()); Priority Order: Only scripts truly needed for initial render should be in <head> without defer/async. Everything else should defer or async. Inline critical CSS, load rest asynchronously.
Step 5: Optimize Web Font Loading
Web fonts can delay text rendering and cause layout shift, both harming LCP. Optimize font loading to prevent invisible text and layout jumps.
Preload Critical Fonts
<link
rel="preload"
href="/fonts/inter-var.woff2"
as="font"
type="font/woff2"
crossorigin
/> Use font-display: swap
Show fallback text immediately while custom font loads:
@font-face {
font-family: 'Inter';
src: url('/fonts/inter-var.woff2') format('woff2');
font-weight: 100 900;
font-display: swap; /* Show text immediately with fallback font */
} Self-Host Fonts
Self-hosting fonts eliminates DNS lookup and connection time to Google Fonts:
- Download WOFF2 files from Google Fonts or use google-webfonts-helper
- Serve from your domain or CDN
- Set
Cache-Control: public, max-age=31536000, immutable
Impact: Saves 100-200ms by eliminating third-party request.
Subset Fonts
Include only needed characters to reduce file size:
/* Only include Latin characters */
@font-face {
font-family: 'Inter';
src: url('/fonts/inter-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
} Use System Fonts
For fastest loading, use native system fonts:
body {
font-family:
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
"Helvetica Neue", Arial, sans-serif;
} Zero download time, perfectly optimized for each platform.
Step 6: Implement CDN & Caching
Caching stores previously generated responses to serve them faster on repeat visits.
Browser Caching
Set appropriate cache headers for static assets:
# Apache (.htaccess)
<IfModule mod_expires.c>
ExpiresActive On
# Images
ExpiresByType image/webp "access plus 1 year"
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
# CSS and JavaScript
ExpiresByType text/css "access plus 1 year"
ExpiresByType application/javascript "access plus 1 year"
# Fonts
ExpiresByType font/woff2 "access plus 1 year"
</IfModule> CDN Configuration
Configure CDN edge caching for maximum performance:
- Static assets: Cache for 1 year with immutable flag
- HTML pages: Cache for 5-10 minutes with stale-while-revalidate
- API responses: Cache based on data freshness requirements
Service Worker Caching
Cache resources locally for offline access and instant repeat visits:
// service-worker.js
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('v1').then((cache) => {
return cache.addAll([
'/styles/critical.css',
'/images/hero-800w.webp',
'/fonts/inter-var.woff2'
]);
})
);
}); Step 7: Monitor & Maintain LCP
LCP optimization is ongoing. Monitor performance and address regressions quickly.
Real User Monitoring (RUM)
- Google Search Console: Core Web Vitals report shows real-user LCP data
- Chrome UX Report: Public dataset with field data for 8M+ origins
- Web Vitals JavaScript library: Track LCP on your own analytics
import {onLCP} from 'web-vitals';
onLCP((metric) => {
// Send to analytics
gtag('event', 'web_vitals', {
event_category: 'Web Vitals',
event_label: metric.id,
value: Math.round(metric.value),
metric_name: 'LCP',
non_interaction: true,
});
}); Lab Testing Tools
- PageSpeed Insights: Shows both lab and field data
- Lighthouse in Chrome DevTools: Detailed diagnostic information
- WebPageTest: Test from multiple locations and devices
- Calibre/SpeedCurve: Continuous monitoring with alerting
Set Up Performance Budgets
Create thresholds to catch regressions:
// Lighthouse CI budget.json
{
"path": "/*",
"timings": [
{
"metric": "largest-contentful-paint",
"budget": 2500
}
],
"resourceSizes": [
{
"resourceType": "image",
"budget": 500
}
]
} Pro Tip: Run Rankture's free SEO audit weekly to monitor your LCP and other Core Web Vitals. Our tool tracks changes over time and alerts you to regressions before they impact rankings.
Common LCP Mistakes to Avoid
❌ Lazy Loading the LCP Element
Mistake: Adding loading="lazy" to your hero image delays its load.
Fix: Use loading="eager" and fetchpriority="high" on LCP images.
❌ Missing Width/Height Attributes
Mistake: Images without dimensions cause layout shift and delayed LCP.
Fix: Always include width and height attributes: <img width="800" height="450">
❌ Client-Side Rendering Without SSR
Mistake: JavaScript frameworks that render content client-side delay LCP until JS executes.
Fix: Use Server-Side Rendering (Next.js, Nuxt.js) or Static Site Generation (Astro, Hugo) to deliver pre-rendered HTML.
❌ Oversized Hero Images
Mistake: Using 3000×2000px images displayed at 800×533px.
Fix: Generate appropriately sized images and use srcset for responsive delivery.
❌ Too Many Preload Links
Mistake: Preloading 10+ resources creates bandwidth contention.
Fix: Preload only 1-3 truly critical resources (LCP image, critical CSS, critical font).
❌ Carousels as LCP Element
Mistake: Auto-rotating carousels change the LCP element, causing poor scores.
Fix: Use static hero images or disable auto-rotation. Preload first slide image.
Frequently Asked Questions
What is a good LCP score?
A good Largest Contentful Paint (LCP) score is 2.5 seconds or less. Google considers 2.5s-4.0s as "needs improvement" and anything over 4.0s as "poor". To pass Core Web Vitals assessment, 75% of your page loads must achieve LCP under 2.5 seconds. Mobile devices typically have slower LCP than desktop, so prioritize mobile optimization.
How do I find my LCP element?
Use Chrome DevTools to identify your LCP element: Open DevTools (F12), go to Performance tab, click Record and refresh the page. In the timeline, look for "LCP" marker. You can also use Lighthouse in DevTools, PageSpeed Insights, or Web Vitals Chrome extension. The LCP element is usually your largest above-the-fold image, video thumbnail, or text block with background image.
Does LCP affect SEO rankings?
Yes, LCP is one of three Core Web Vitals metrics that Google uses as a ranking factor since June 2021. While content quality and relevance remain primary ranking factors, sites with better LCP scores have a competitive advantage. Google data shows that sites meeting Core Web Vitals thresholds have 70% lower bounce rates and higher engagement.
What causes slow LCP?
The most common causes of slow LCP are: unoptimized images (large file sizes, wrong formats), slow server response times (TTFB over 800ms), render-blocking CSS and JavaScript, lazy loading the LCP element, web fonts causing layout shift, and inefficient client-side rendering. Hero images are often the culprit since they are frequently the LCP element.
Should I lazy load my hero image?
No, never lazy load your hero image or LCP element. This delays loading and worsens LCP. Instead, preload your LCP image with <link rel="preload" as="image" href="hero.jpg" fetchpriority="high">. Use lazy loading only for below-the-fold images. Loading="eager" on your hero image also prevents accidental lazy loading by frameworks.
How long does it take to see LCP improvements?
You can see LCP improvements immediately in lab testing tools like Lighthouse and PageSpeed Insights after deploying optimizations. However, real-user data in Google Search Console and Chrome UX Report takes 28 days to update, as it uses a 28-day rolling average. Deploy fixes, monitor lab metrics for 1-2 days, then check field data after 4 weeks.
Ready to Optimize Your LCP?
Run a free SEO audit with Rankture to see your current LCP score and get personalized recommendations. Our tool analyzes your Core Web Vitals and shows exactly which images and resources are slowing you down.
Related Articles
INP Optimization Guide
Fix Interaction to Next Paint - Google's newest Core Web Vital (replaced FID)
Core Web Vitals Monitoring
Automate LCP, INP, and CLS tracking with alerts
Competitor SEO Analysis
Compare your Core Web Vitals against competitors side-by-side
Local SEO Audit
Find why you're not ranking in "near me" searches