Evaluat is in private access. Demos open through June. Book a slot
Learn · Concept

Largest Contentful Paint (LCP), explained for engineers

Largest Contentful Paint is the moment the biggest thing your user came to see finishes rendering. Google ranks it a Core Web Vital. Here is what it measures, what trips it up, and how to test it under load without lying to yourself.

Updated

What LCP measures

LCP is a Core Web Vital. It is the time, from navigation start, until the largest visible element on the page finishes rendering. The “largest” is measured by pixel area inside the viewport at the moment of paint.

The browser tracks LCP automatically as it renders the page. It keeps a running candidate, updating whenever a larger element paints. The final LCP value reported is the last candidate before the user starts interacting with the page. Any tap, scroll, or key press halts the measurement.

LCP correlates with the subjective experience of “the page loaded”. The hero image is in. The headline is visible. The video poster is up. The user can start reading or clicking.

What counts as an LCP element

The browser considers a constrained set of element types as LCP candidates:

  • <img> and <image> (inside SVG)
  • <video> poster frames
  • Elements with a background-image set via CSS
  • Block-level elements containing text nodes

Inline SVGs, decorative pseudo-elements, and elements hidden by opacity: 0 or fully clipped by clip-path are excluded. The candidate must intersect the viewport and have a final paint size; partially-loaded images do not count until the load completes.

This matters because the LCP element is rarely the one you would guess. A 1200x600 hero image is the usual suspect, but on a content-heavy page with no hero, the LCP might be a paragraph of text. On a product page, it might be the product image. On a video player, it might be the poster frame. Always check before optimising.

The field vs lab gap

Two different worlds measure LCP, and they disagree more often than teams expect.

Field data comes from real users via the Chrome User Experience Report (CrUX) or your own Real User Monitoring. It is what your customers actually experience: their networks, their CPUs, their cached or uncached visits, every browser tab they have open. CrUX reports the 75th percentile over a 28-day window. RUM gives you per-session data.

Lab data comes from synthetic measurement. PageSpeed Insights, Lighthouse, WebPageTest, and real-browser load testing platforms all run controlled tests against a target URL. The environment is fixed: known network throttling, known CPU profile, known viewport. Results are reproducible.

The gap appears because lab tests run one browser at a time, on a fast network, with no competing tab activity, and usually against a server with no concurrent load. Real users hit a server already serving thousands of others, on flaky mobile networks, with eight tabs open. Their LCP is worse.

This is where real-browser load testing earns its place. Run a 1,000-virtual-user test against your production-shaped server. Now every virtual user is a real browser firing real requests at a server under real contention. The LCP that comes back is calibrated to peak load, not to ideal conditions.

What pushes LCP up

The usual culprits, ranked by how often we see them on demo calls:

  1. Slow server response (TTFB). The LCP HTML chunk has not arrived yet. Everything else is moot. Real-browser load tests expose this because TTFB visibly worsens as concurrency rises.
  2. Render-blocking resources. CSS in <head> with no media attribute, synchronous JavaScript, web fonts. The browser cannot paint until these resolve.
  3. The LCP image is not preloaded. The image discovery happens late in the render path, so the request fires after layout. A <link rel="preload"> for the LCP image cuts hundreds of milliseconds.
  4. CDN cache misses on the LCP asset. If the LCP image is uncached at the edge for first-time visitors, you will see LCP spikes on the cold-cache portion of your traffic.
  5. Third-party tags blocking the main thread. Analytics, A/B testing, consent banners. They delay paint by occupying the JavaScript engine when it should be rendering.
  6. Layout thrashing during render. Web fonts that swap mid-paint trigger reflow. Late-arriving stylesheets recompute the entire DOM. Both reset the LCP candidate.

How to test LCP honestly

Treat lab and field as complementary. RUM tells you what is happening. Lab tells you what would happen if you changed something.

For lab measurement at scale, real-browser load testing is the right tool. Every virtual user is a real Chromium instance with its own memory, cache, and network stack. The LCP capture is native to the browser, not a heuristic. The numbers match what your customers’ browsers would record under the load you are testing.

If you also need per-page Vitals budgets enforced in CI, the same scenarios run as post-deploy smoke checks (the Testing Suite roadmap covers this). The build fails when LCP busts the budget on a critical page.

Common mistakes

  • Measuring LCP without load. A 1.8s LCP on Lighthouse means little if your peak-traffic LCP is 5.2s.
  • Optimising the wrong element. Verify the LCP candidate before swapping the hero image format. The LCP might be a paragraph.
  • Reporting the mean. The 75th percentile is the published threshold. The 99th percentile is the customer support backlog.
  • Treating LCP as a one-off. Web Vitals drift. A third-party tag added six weeks ago might have pushed LCP up 400ms with no other code change.

LCP is one of three Core Web Vitals. The companion metric for responsiveness is Interaction to Next Paint, which replaced First Input Delay in March 2024.

Common questions

FAQ

How does LCP differ from First Contentful Paint (FCP)?

FCP is the moment any content paints. LCP is the moment the largest visible element finishes painting. FCP fires earlier and is less correlated with how users describe a page as "loaded".

What counts as an LCP candidate element?

Block-level text, images (img, background-image), poster frames for video, and SVG elements that are visible in the initial viewport. The browser tracks the largest of these as it paints, and the last reported one before user interaction becomes the LCP.

What is a good LCP target?

Google's Core Web Vitals threshold is 2.5 seconds at the 75th percentile of users. Above 4 seconds is classified as poor. The 75th percentile is the part that bites: an average LCP of 2.4s often hides a long tail of users hitting 6+ seconds at peak.

Why does load testing matter for LCP?

LCP under no concurrency is often optimistic. Under real load, the LCP image gets queued behind third-party tags, the LCP HTML chunk gets delayed by CPU contention on the server, and the LCP web font loads slower because the CDN is saturated. Synthetic real-browser load testing captures all three.

See it on your site

Test in real browsers.
Debug in real sessions.

Want to see this measured on your app?

30 minutes. We build a scenario on your real customer journey, run a small test, and walk you through the report with your data in it.

Sample report walkthrough
30s video · 16:9