What Is Largest Contentful Paint (LCP)?
Largest Contentful Paint (LCP) is a Core Web Vital that measures how quickly the largest visible content element renders on a page. It captures the moment when the main content of the page has finished rendering in the user's viewport — the moment when the page "looks loaded" to a human eye, not just to the network stack. Of Google's three Core Web Vitals, LCP is widely considered the most direct measure of perceived loading speed.
Where older metrics like DOMContentLoaded or load-complete fired based on technical milestones that had little to do with what the user could see, LCP was designed to reflect actual user experience. It does not care that a 2MB JavaScript analytics bundle is still downloading in the background if the hero image and headline are already on screen. Conversely, a page whose HTML arrived in 300ms but whose main image takes 6 seconds to paint has terrible LCP even though most network-level metrics would look fine.
LCP is part of Google's Core Web Vitals alongside Cumulative Layout Shift (CLS) and Interaction to Next Paint (INP). Together, they form the page experience signals that Google uses in ranking. LCP is the one most developers spend the most time fighting, because it touches everything: server performance, network path, render blocking, image optimization, font loading, and client-side hydration.
What Elements Can Be the LCP?
LCP considers the largest of these element types in the visible viewport:
<img>elements<image>elements inside SVG<video>poster images- Elements with a background image loaded via CSS (e.g.
background-image: url(...)) - Block-level elements containing text nodes (paragraphs, headings, divs with text)
On most content sites, the LCP element is the hero image, a large banner, a featured video poster, or the main headline if there is no dominant image above the fold. On e-commerce product pages, it is almost always the primary product photograph. On landing pages with lots of text, it is often the H1 or a large paragraph.
What is not counted as LCP
LCP ignores:
- Elements outside the viewport (below the fold)
- Elements with opacity 0 (invisible)
- Images that cover the full viewport or are larger than the viewport (treated as background, excluded in some cases)
- Placeholder images that are later replaced — only the final rendered content counts once it appears
<iframe>content — the iframe itself may be the LCP but its internal content is not evaluated
What Is a Good LCP Score?
Google's thresholds are based on the 75th percentile of page loads across both mobile and desktop, measured via the Chrome User Experience Report (CrUX).
| LCP Time | Rating | User Experience |
|---|---|---|
| 0 - 2.5 seconds | Good | Page feels fast; users see content quickly |
| 2.5 - 4.0 seconds | Needs Improvement | Noticeable delay; some users become impatient |
| Over 4.0 seconds | Poor | Significant delay; high bounce risk |
To be rated "Good", 75% of visits to the page must have an LCP at or below 2.5 seconds. Field data (real users in CrUX) is what counts for Google's ranking signals; lab data (single Lighthouse test) approximates it but can diverge dramatically depending on device, network, and content variations.
Why LCP Matters for SEO
LCP is the most heavily weighted of the Core Web Vitals for perceived performance, and it has a direct, measurable relationship with user behaviour. Multiple industry studies have found:
- Every 1 second of additional load time (roughly tracking LCP) correlates with a 20-40% drop in conversion rate on retail sites
- Pages with "Poor" LCP have 2x the bounce rate of pages with "Good" LCP in the same topical category
- Google has confirmed Core Web Vitals are a ranking factor, particularly as a tiebreaker in competitive SERPs
- LCP is often the single biggest performance gap between top-ranking pages and challenger sites
Beyond ranking directly, LCP is the most visible performance issue to both users and stakeholders. When someone says a site "feels slow", they are usually talking about LCP, not some abstract metric like Total Blocking Time. Fix LCP and people notice.
How LCP Is Measured
LCP is reported via the Largest Contentful Paint API, which emits a PerformanceEntry every time a larger content element finishes rendering. The final LCP value is the largest element rendered before the user interacts with the page or the tab is backgrounded.
Key nuances:
- User interaction stops measurement — if the user clicks or scrolls before the LCP would have been recorded, the metric is finalized at whatever value it had
- Page visibility matters — if the tab is backgrounded during load, LCP is not recorded for that session
- LCP can update multiple times — the API emits entries as larger elements are rendered; only the final entry before interaction counts
- Field vs lab: field data (real users) captures edge cases, slow devices, and real network conditions; lab data (controlled simulation) gives reproducible numbers but may miss real-world variance
Common Causes of Poor LCP
1. Slow Time to First Byte (TTFB)
TTFB is the time from request to the first byte of the HTML response. Everything downstream is gated by it — the browser cannot even start parsing HTML, let alone load the LCP element, until TTFB completes. Slow TTFB is caused by:
- Slow origin servers (underpowered hosting, unoptimized application code)
- Uncached database queries on dynamic pages
- Distant origin with no CDN (user in Australia, server in the US)
- Heavy middleware (redirects, rewrites, auth checks)
- Cold starts on serverless functions
Target: TTFB under 200ms for static pages, under 600ms for most dynamic pages.
2. Render-blocking resources
CSS and synchronous JavaScript in the <head> must finish downloading and parsing before the browser can render any pixels. A single blocking CSS file on a slow connection can add seconds to LCP even if the HTML arrived fast.
3. Large, unoptimized images
If the LCP element is an image, its size and format determine the lower bound on LCP. A 3MB JPEG hero image on a 4G connection needs several seconds just for the bytes to arrive, regardless of everything else. Use WebP or AVIF, size the image to the display size, and apply lossy compression — see how to optimize images for SEO.
4. Client-side rendering (CSR)
Single-page apps that rely entirely on JavaScript to render content have especially bad LCP. The browser receives a near-empty HTML shell, downloads megabytes of JavaScript, executes it, fetches data from APIs, and only then renders the actual page. On low-end mobile devices, this can push LCP past 10 seconds.
5. Web font loading
If the LCP element is text and uses a web font with font-display: block, the text may not paint until the font downloads. Switch to font-display: swap or optional to render the text immediately in a fallback font.
6. Lazy loading the LCP image
The loading="lazy" attribute delays image loading until the element is near the viewport. If applied to the hero image, it can add hundreds of milliseconds of delay because the browser has to do layout and viewport calculation before triggering the download.
7. Late-discovered images
Images only referenced in CSS (background images) or loaded dynamically via JavaScript are discovered late in the page lifecycle. The browser's preload scanner does not find them until the relevant CSS or JS has been parsed. That alone can push LCP by a second or more.
8. Slow third-party resources
Fonts from Google Fonts, scripts from ad networks, tag managers, chat widgets — if any of these are render-blocking, they extend LCP.
How to Improve LCP: A Developer's Playbook
Step 1: Identify your LCP element
Before fixing anything, know what you are fixing. Chrome DevTools > Performance tab, record a page load, and the LCP marker will point to the exact element. PageSpeed Insights also shows the LCP element and its timing breakdown.
Step 2: Reduce TTFB
Before you optimize the LCP element itself, shorten the time until the browser even knows it exists.
- Use a CDN — Cloudflare, Fastly, AWS CloudFront, Vercel, Netlify all reduce TTFB by serving from edge locations close to users
- Cache aggressively — full-page caching (Varnish, Redis, Cloudflare Cache Rules) can drop TTFB from 800ms to 30ms
- Optimize database queries — slow SQL is a common TTFB killer; add indexes, cache results, batch where possible
- Use HTTP/2 or HTTP/3 — multiplexed connections reduce head-of-line blocking
- Pre-warm critical routes — background refresh cache before it expires (stale-while-revalidate)
Step 3: Preload the LCP resource
Tell the browser about the LCP resource in the HTML head so it starts downloading immediately, in parallel with HTML parsing:
<link rel="preload" as="image" href="/hero.webp" fetchpriority="high">
For responsive images, use the imagesrcset and imagesizes attributes:
<link rel="preload"
as="image"
href="/hero-800.webp"
imagesrcset="/hero-400.webp 400w, /hero-800.webp 800w, /hero-1600.webp 1600w"
imagesizes="(max-width: 600px) 400px, 800px"
fetchpriority="high">
Step 4: Use fetchpriority="high" on the LCP image
Available since Chrome 101, the fetchpriority attribute boosts the priority of the image in the browser's fetch queue. For the LCP element, it can shave hundreds of milliseconds:
<img src="/hero.webp" width="1200" height="630" alt="Hero banner" fetchpriority="high">
Step 5: Never lazy-load the LCP image
If the LCP image is in the initial viewport, it must load eagerly. Do not add loading="lazy" to above-the-fold images. You can lazy-load everything below the fold.
Step 6: Optimize image size and format
- Use WebP or AVIF instead of JPEG/PNG (50-70% smaller at similar quality)
- Compress aggressively — quality 75-80 is usually indistinguishable from 90+ visually
- Size the image to its display size — do not serve 4000px images to 800px containers
- Use
srcsetto serve smaller images on smaller devices - Consider responsive art direction (
<picture>+<source>) to crop differently at different breakpoints
Step 7: Reduce render-blocking resources
Every blocking CSS or synchronous script in the head extends LCP. Techniques:
- Inline critical CSS — the CSS needed to render above-the-fold content, inlined in a
<style>tag in the head (typically 10-20KB) - Defer non-critical CSS — load with
<link rel="preload" href="..." as="style" onload="this.rel='stylesheet'"> - Defer or async all non-critical JavaScript — see the script loading checker for an audit
- Remove unused CSS — tools like PurgeCSS, UnCSS, and the Coverage tab in DevTools help identify it
Step 8: Optimize web fonts
- Self-host fonts (avoid extra DNS lookup + TLS handshake to fonts.googleapis.com)
- Use WOFF2 format (much smaller than WOFF or TTF)
- Preload the woff2 file with
<link rel="preload"> - Use
font-display: swaporoptionalto avoid blocking text paint - Subset fonts to only the characters you need
Step 9: Consider server-side rendering or static generation
If you are on a client-side rendered SPA with poor LCP, moving to SSR (Next.js, Nuxt, Remix, SvelteKit) or SSG can transform LCP. The HTML is fully rendered server-side, so the browser can show content as soon as the HTML arrives — no waiting for JS to hydrate.
Step 10: Use a CDN for images
Image CDNs like Cloudflare Images, Imgix, Cloudinary, and Bunny.net automatically resize, compress, and serve images in the best format for the user's device — often cutting image bytes by 70%+ and shaving seconds from LCP.
The LCP Breakdown: Four Sub-Phases
Google's team recommends thinking of LCP as four sub-parts. Optimizing each one independently is the most systematic way to improve LCP.
| Sub-Phase | What It Measures | Target |
|---|---|---|
| TTFB | Server response time | < 200-600ms |
| Resource load delay | Time between TTFB and when the LCP resource starts downloading | < 0ms ideally |
| Resource load time | Time to download the LCP resource | As short as bandwidth allows |
| Element render delay | Time between resource arriving and element painting | < 0ms ideally |
Each sub-phase has distinct optimizations. A long resource load delay usually means the resource is not preloaded or not discovered by the preload scanner. A long element render delay suggests render-blocking CSS or font issues.
LCP in Code: Real Patterns
Pattern 1: Hero image optimized correctly
<!-- In <head> -->
<link rel="preload"
as="image"
href="/hero-1200.webp"
imagesrcset="/hero-800.webp 800w, /hero-1200.webp 1200w, /hero-1800.webp 1800w"
imagesizes="100vw"
fetchpriority="high">
<!-- In <body>, near the top -->
<img
src="/hero-1200.webp"
srcset="/hero-800.webp 800w, /hero-1200.webp 1200w, /hero-1800.webp 1800w"
sizes="100vw"
width="1200"
height="630"
alt="Summer sale banner"
fetchpriority="high">
Pattern 2: Inline critical CSS
<head>
<style>
/* 14KB of critical above-the-fold CSS inlined here */
body { margin: 0; font-family: system-ui, sans-serif; }
.hero { min-height: 500px; background: #111; color: #fff; }
/* ...etc... */
</style>
<link rel="preload" href="/main.css" as="style" onload="this.rel='stylesheet'">
</head>
Pattern 3: Deferred non-critical JS
<script src="/analytics.js" defer></script>
<script src="/chat-widget.js" async></script>
<script type="module" src="/app.js"></script> <!-- modules are deferred by default -->
Tools to Measure LCP
PageSpeed Insights
Google's PageSpeed Insights at pagespeed.web.dev shows both lab (Lighthouse) and field (CrUX) LCP for any public URL. The Opportunities section pinpoints LCP issues with specific element and timing breakdowns.
Lighthouse in Chrome DevTools
Open DevTools, run a Lighthouse audit. The Performance section highlights LCP and shows the element, its timing, and what contributed to the delay.
Chrome DevTools Performance Panel
Record a page load, look for the LCP marker in the timings lane. Click it for the LCP element and full timing sub-phases. Indispensable for deep debugging.
Web Vitals Chrome Extension
Lightweight overlay showing LCP, CLS, and INP as you browse. Free and open source from Google.
Search Console Core Web Vitals report
Aggregates CrUX data for your verified domain, groups URLs by CWV status. Shows how many URLs have "Poor" LCP in your index.
web-vitals library
The web-vitals JavaScript library from Google sends real-user LCP data from your visitors to your analytics endpoint. Essential for ongoing monitoring:
import { onLCP } from "web-vitals";
onLCP((metric) => {
navigator.sendBeacon("/rum", JSON.stringify(metric));
});
RankNibbler performance tools
Run any URL through the RankNibbler website speed test for LCP, CLS, INP and a list of fixes. The full audit layers in image optimization checks, render-blocking detection, and script loading analysis.
LCP in Popular Frameworks
Next.js
The <Image> component from next/image auto-generates responsive srcsets, serves modern formats, and applies priority prop to preload. For the LCP image: <Image src="/hero.jpg" width="1200" height="630" alt="..." priority />
React + Vite
Use standard <img> with preload in the HTML head. Consider vite-imagetools or vite-plugin-image for build-time optimization.
Nuxt
<NuxtImg> component does automatic optimization and responsive srcsets. For LCP: add preload and fetchpriority="high".
WordPress
Since WordPress 6.3, priority loading is automatic for above-the-fold images. Use plugins like Perfmatters, WP Rocket, or FlyingPress for critical CSS inlining and lazy-load control. Offload images to a CDN for best results.
Astro
The <Image> component handles responsive images; use loading="eager" and fetchpriority="high" on the LCP element. Astro's zero-JS default is a huge LCP advantage.
Common Mistakes That Tank LCP
- Lazy-loading the hero image — adds unnecessary delay and can even prevent preload
- Using a background image in CSS for the hero — late-discovered, impossible to preload unless explicitly hinted
- Loading Google Fonts with blocking syntax — use
display=swapor self-host - Serving 4K images to 600px containers — wastes bandwidth and CPU
- Inlining giant base64 images in HTML — inflates HTML size and delays TTFB
- Third-party scripts in the head (non-async) — render-blocking until they load
- Misconfigured CDN — cache misses on images, slow origin pulls
- Synchronous A/B test snippets — classic LCP killer, easily 500ms+ added
- Not specifying image dimensions — also hurts CLS
- Rendering everything in JavaScript on a slow phone — unsolvable without SSR
LCP vs Other Core Web Vitals
| Metric | Measures | Good Threshold | Main Fix |
|---|---|---|---|
| LCP | Loading speed of largest element | ≤ 2.5s | Optimize LCP element, reduce TTFB, preload |
| CLS | Visual stability | ≤ 0.1 | Reserve space for dynamic content |
| INP | Interaction responsiveness | ≤ 200ms | Break up long main-thread tasks |
Case Study: Cutting LCP from 5.2s to 1.8s
An e-commerce site selling outdoor gear had a field LCP of 5.2s on product pages — deep in the "Poor" range. After audit:
- Hero product image was 4.1MB JPEG at native 4000x3000 resolution, displayed at 800x600
- Hero image was lazy-loaded (
loading="lazy") - Hero image was a CSS background — not discoverable by preload scanner
- 3 render-blocking third-party scripts in head (chat, analytics, A/B testing)
- Google Fonts loaded from fonts.googleapis.com with default blocking behavior
- TTFB 1.1s due to uncached product queries
Remediation:
- Switched hero from CSS background to HTML
<img>with width/height - Converted to WebP at 85% quality and served responsive srcset (400/800/1600px widths)
- Removed lazy-load attribute, added
fetchpriority="high" - Added
<link rel="preload" as="image" ...>in head - Moved all third-party scripts to async/defer
- Self-hosted fonts with
font-display: swap - Added Redis cache for product queries, bringing TTFB to 180ms
Result: field LCP dropped to 1.8s over 28 days. Conversion rate rose 18% on the affected pages; organic traffic rose 12% as Google upgraded the page experience signal.
Monitoring LCP in Production
Lab data from Lighthouse is a single snapshot under controlled conditions. Real users vary in device, network, cache state, geography, and time of day. You need real-user monitoring (RUM).
Basic web-vitals integration
import { onLCP } from "web-vitals/attribution";
onLCP((metric) => {
const body = {
name: metric.name,
value: metric.value,
rating: metric.rating,
element: metric.attribution.element,
url: metric.attribution.url,
loadTime: metric.attribution.lcpResourceEntry?.duration,
};
navigator.sendBeacon("/rum", JSON.stringify(body));
});
Attribution data
The web-vitals/attribution module gives per-metric breakdowns — which element was the LCP, what resource it loaded, how long each sub-phase took. This lets you spot regressions precisely.
RUM services
SpeedCurve, DebugBear, Calibre, Sentry, New Relic Browser, Akamai mPulse all offer LCP monitoring with alerts and per-page dashboards. Essential at scale.
Frequently Asked Questions
What is a good LCP score?
2.5 seconds or less is rated "Good" by Google at the 75th percentile.
Is LCP a Google ranking factor?
Yes. LCP is part of Core Web Vitals, which Google uses as a page experience ranking signal.
How is LCP different from First Contentful Paint (FCP)?
FCP measures when the first piece of content appears (could be a small logo or placeholder). LCP measures when the largest content element appears — a much closer proxy for "page feels loaded".
Why does my LCP vary between tests?
Lab tests simulate one environment; real users vary enormously. Field data from CrUX aggregates 28 days of real visits and is what Google uses for ranking.
What is the biggest single LCP improvement I can make?
Identify your LCP element (usually the hero image), preload it, remove lazy-load, and compress it aggressively. That combination is often 40-60% of total LCP wins.
Can I lazy-load the LCP image?
No. Lazy-loading the LCP image adds significant delay. Only lazy-load images below the fold.
Does LCP include time on the server?
Yes. TTFB is a sub-component of LCP, so slow server response directly increases LCP.
Does the LCP element change during page load?
It can. As larger elements render, the LCP entry updates. The final value recorded before user interaction is the reported LCP.
How do I find my LCP element?
Chrome DevTools > Performance > record a page load > look at the timings lane for the LCP marker. Or use PageSpeed Insights, which shows the element directly.
Is LCP the same on mobile and desktop?
The calculation is the same, but results differ because mobile devices are slower, viewports are smaller (different element may be largest), and networks are often slower. Google uses mobile field data primarily for mobile-first indexed sites.
Do iframes count as LCP elements?
The iframe container can be the LCP element, but its internal content is not evaluated separately.
Should I use <picture> element for the LCP image?
Yes, when art direction matters (different crops at different breakpoints). For simple responsive images, srcset on <img> is sufficient and works well with preload.
How quickly do LCP improvements show in Search Console?
Field data in CrUX is a 28-day rolling window. Meaningful changes take 4-6 weeks to fully reflect. Lab data reflects changes immediately.
LCP Sub-Phase Deep Dive
To improve LCP systematically, understanding which sub-phase dominates your measurement is critical. A 4-second LCP with 3 seconds of TTFB is an entirely different problem from a 4-second LCP with 2 seconds of load time and 0.5s TTFB.
Diagnosing long TTFB
If TTFB is over 600ms for most visits, server-side work is your bottleneck. Common diagnostics:
- Server-timing HTTP header: Add
Server-Timingheaders from your app to see DB query times, cache lookup times, template render times. Chrome DevTools displays them in the Network panel under "Timing". - Database query profiling: New Relic, Datadog APM, or your language's built-in profiler will show the 5 slowest queries, which are usually 80% of DB time.
- Third-party API dependencies: Is your page server-rendering data from a slow upstream API? Cache the upstream response, or render a skeleton first and hydrate the dynamic part client-side after TTFB.
- CDN cache hit rate: If your CDN cache hit rate is below 90% for static pages, check cache rules, Vary headers, and query-string handling. Many sites unintentionally make cache keys too specific.
Diagnosing long resource load delay
The gap between TTFB and when the LCP resource starts downloading. Ideal: near zero. Common causes of delay:
- LCP resource not discovered in HTML: If the LCP element is a CSS background-image or a JS-injected image, the preload scanner cannot find it during HTML parse. Move to an
<img>tag or add<link rel="preload">. - Low fetch priority: By default, in-viewport images get "High" priority, but off-viewport or dynamic images get "Low". Add
fetchpriority="high"to the LCP image. - Connection limits: Browsers cap concurrent connections per origin (~6 for HTTP/1, unlimited for HTTP/2). Serving LCP image from the same origin as many other resources can stall it behind lower-priority requests.
Diagnosing long resource load time
The actual download. Bottlenecks:
- Large file size: Compress, resize, convert to modern format. A 1.2MB JPEG becomes a 220KB WebP becomes a 150KB AVIF with no visible quality loss.
- Slow CDN edge: Check CDN point-of-presence mapping. Some CDNs serve US users from an East Coast edge even when the user is in California — moving to a better CDN or using image CDNs with global edge can halve download time.
- HTTP/1 head-of-line blocking: Switching to HTTP/2 or HTTP/3 lets the browser multiplex requests over a single connection, eliminating the bottleneck.
- TLS handshake overhead: For cross-origin resources, the initial TLS handshake can add 100-300ms.
preconnectto critical origins warms the connection.
Diagnosing long element render delay
The gap between resource arrival and element paint. Causes:
- Render-blocking CSS: CSS must be parsed before any paint can happen. Inline critical CSS, defer non-critical CSS.
- Slow-loading web fonts affecting the LCP text: If your LCP is text and the font is taking 2s to load with
font-display: block, the text cannot paint until the font arrives. Switch toswaporoptional. - JavaScript hydration for framework pages: React/Vue/Angular pages may have all the HTML available but delay interactivity until JS hydrates. The visual LCP itself is usually pre-hydration, but check with the Performance panel.
- Heavy main-thread work: If JavaScript is chewing up the main thread at the moment LCP wants to paint, paint is delayed. Break up long tasks, defer non-critical scripts.
LCP and the Soft Navigation Problem
Traditional LCP measurement stops at first paint of the largest element on initial page load. Single-page apps that navigate without full page reloads (React Router, Next.js client-side nav, etc.) do not trigger a new LCP measurement by default. The W3C is actively developing the Soft Navigations API to address this — Chrome already emits soft-navigation LCP entries experimentally. Monitor this space if you run an SPA; the metric will become measurable in production RUM tools over the next year.
LCP Optimization for AMP Pages
Accelerated Mobile Pages (AMP), while declining in usage since Google removed the "AMP required for Top Stories" requirement in 2021, still exists. AMP pages have built-in LCP optimizations:
<amp-img>enforces width/height attributes- Resources are lazy-loaded and prioritized by the AMP runtime
- Critical CSS is inlined automatically
- JavaScript is restricted to the AMP runtime + allow-listed components
These produce excellent LCP by default — typically under 1 second on mid-range connections. If you maintain AMP alongside your canonical HTML, the AMP version often provides a usable CWV benchmark for your LCP target.
LCP in Single-Page Apps
SPAs built with React, Vue, Angular, or Svelte are traditionally LCP weak points because of the JavaScript waterfall: HTML -> JS download -> JS parse/execute -> data fetch -> render. Modern patterns that address this:
Server-side rendering (SSR)
Render initial HTML on the server, then hydrate on the client. Frameworks: Next.js, Nuxt, SvelteKit, Remix. LCP benefits because meaningful content is present in the initial HTML.
Static site generation (SSG)
Render HTML at build time, serve from CDN. Fastest possible LCP because HTML is pre-cached at edge locations. Frameworks: Next.js, Astro, Gatsby, 11ty, Hugo, Jekyll.
Streaming SSR
Send HTML in chunks as the server renders, so the browser can start painting before the entire page is ready. React 18 Suspense + Next.js App Router support this natively.
Islands architecture
Ship only the JavaScript needed for interactive "islands" within otherwise-static HTML. Astro popularized this; Qwik takes it further with resumable hydration. LCP benefits from minimal JS shipping.
Partial hydration
React Server Components and similar approaches run code on the server without shipping it to the client. Reduces the JS bundle and improves LCP for content-heavy pages.
LCP for High-Traffic Images
The LCP image is often your most-viewed asset. Optimizing it thoroughly pays off at every page load:
Optimal image formats
- AVIF — best compression (30-50% smaller than WebP), supported in Chrome 85+, Firefox 93+, Safari 16.4+
- WebP — near-universal support (95%+ of traffic), 25-35% smaller than JPEG
- JPEG XL — next-gen format, limited support as of 2026
- JPEG — fallback, universally supported
Use <picture> with <source type="..."> to serve the most efficient format each browser supports:
<picture>
<source type="image/avif" srcset="/hero.avif">
<source type="image/webp" srcset="/hero.webp">
<img src="/hero.jpg" width="1200" height="630" alt="Hero" fetchpriority="high">
</picture>
Responsive images
Serve different sizes for different viewports:
<img
src="/hero-1200.webp"
srcset="/hero-400.webp 400w, /hero-800.webp 800w, /hero-1200.webp 1200w"
sizes="(max-width: 600px) 100vw, (max-width: 1200px) 80vw, 1200px"
width="1200"
height="630"
alt="Hero banner"
fetchpriority="high">
Progressive rendering
Progressive JPEGs render as low-res placeholders and sharpen as more bytes arrive. Useful on slow connections — though LCP uses final paint, not first paint, so progressive only helps perceived speed, not the metric itself.
Placeholder strategies
- LQIP (Low-Quality Image Placeholders): tiny, blurred version inline as base64, swapped to full-quality when loaded
- Dominant color placeholders: CSS background color matching the image's average color
- Blur-up (BlurHash, ThumbHash): compact algorithm-generated placeholders
Placeholders improve perceived speed but the LCP metric cares about the final content paint, not the placeholder.
LCP and HTTP/2 / HTTP/3
Modern HTTP protocols materially improve LCP on most real-world networks:
HTTP/2
- Multiplexed streams: multiple requests over one connection, no head-of-line blocking
- Server push (deprecated in Chrome): could push critical resources unsolicited
- Header compression: reduces per-request overhead
HTTP/3 / QUIC
- Runs over UDP instead of TCP, eliminating TCP head-of-line blocking
- Faster connection establishment (0-RTT for repeat connections)
- Better performance on lossy networks (mobile, poor Wi-Fi)
Most CDNs (Cloudflare, Fastly, CloudFront) support HTTP/3 transparently. Check that your origin or CDN has it enabled — it typically cuts LCP 5-15% on mobile networks for zero code change.
LCP Regression Prevention
Optimizing LCP once is easy; keeping it optimized forever is hard. Sites regress when teams ship new code, third-party vendors add scripts, or content editors upload un-optimized images. A prevention program needs:
Performance budgets
Define hard limits per page: maximum JS bundle size, maximum image size for LCP element, maximum TTFB. Fail builds or deployments that exceed them.
Continuous lab testing
Lighthouse CI on pull requests. Catch performance regressions before merge.
Real-user monitoring
web-vitals library plus your analytics. Alert when p75 LCP crosses 2.5s on key pages.
Image upload pipelines
CMS-integrated automatic image compression and format conversion. Content editors should not be able to upload a 10MB photo and have it served as-is — your pipeline should downsize, compress, and convert automatically.
Third-party script governance
Review each new tag in your tag manager for performance impact. Require async/defer. Reject synchronous scripts in the head unless business-critical.
Regular audits
Monthly or quarterly, review the full LCP performance of top landing pages. New issues emerge as content and code evolve.
LCP and AI Overviews
Google's AI Overviews and other AI-generated SERP features may cite your content as a source. Fast LCP is one of the signals used when Google chooses which sources to pull for generative answers — slow, heavy pages are cited less often, presumably because they would add latency to the user's experience if they click through. Fast pages both rank better and get cited more in AI features, compounding the benefits of optimization.
LCP on E-Commerce Product Pages
Product pages are the highest-value, highest-churn pages on e-commerce sites. Poor LCP directly costs revenue — studies consistently find 7-10% conversion lift per second of LCP improvement.
Product image optimization
Product images are typically the LCP element. Optimize aggressively: WebP/AVIF, responsive srcset, preload the primary image. Lazy-load the remaining gallery images.
Personalization without LCP cost
Personalization (recently viewed, recommended products, user-specific pricing) often inflates TTFB or injects content late. Render personalization client-side after initial LCP, not server-side before it. The initial page should be cacheable and fast; personalization layers over after first paint.
Third-party reviews and social proof
Trustpilot widgets, Yotpo reviews, etc. frequently block rendering. Ensure they load async and do not appear above the LCP element. If reviews must appear above the fold, render stub review data server-side and enhance with JavaScript later.
A/B testing without LCP cost
Classic A/B test scripts (Optimizely, VWO) run synchronously in the head to avoid flicker — terrible for LCP. Modern server-side or edge-rendered A/B testing (Vercel Edge, LaunchDarkly server-side) avoids the client-side tax entirely.
Final Thoughts
LCP is where page performance meets real user perception. It is the metric most directly tied to "does this page feel fast?" — the question every user implicitly asks within the first second of landing on your site. Optimizing it pays dividends in conversions, engagement, and rankings that few other changes can match.
The playbook is mature: reduce TTFB, preload the LCP resource, use modern image formats, avoid lazy-loading above the fold, and eliminate render-blocking resources. Apply those systematically, measure field data with web-vitals and PageSpeed Insights, and you will clear the 2.5s threshold on most pages.
Pair LCP work with attention to CLS and overall page speed, plus solid on-page SEO fundamentals, and you build a site that performs well for both users and search engines.
Last updated: March 2026