fastmon Docs
Web Vitals

Largest Contentful Paint (LCP)

What LCP is, what's a good LCP, and how to debug a slow one, with fastmon's data.

LCP measures how long it takes for the largest visible element on a page to show up. It is the moment something meaningful is finally on screen.

LCP is part of Core Web Vitals, Google's standard user-experience set, and it counts toward search ranking.

What's a good LCP?

LCP is reported in milliseconds. Track the 75th percentile across pageviews, as Google does.

LCP at p75Rating
≤ 2,500 msGood
≤ 4,000 msNeeds improvement
> 4,000 msPoor

What counts as the "largest contentful element"

The browser tracks the largest element that has finished painting in the visible viewport. Eligible elements are:

  • <img> and <image> inside <svg>
  • <video> (the poster frame)
  • An element with a background-image set via CSS
  • Block-level text nodes

The "size" is the rendered area on screen, intersected with the viewport. Off-screen content does not count, even if it's bigger.

The "largest" can change as the page loads. The browser emits LCP entries until the user clicks, scrolls, or presses a key. The last entry before that is the LCP value.

When LCP is reported

LCP is finalized:

  • when the user scrolls, clicks, or presses a key (whichever comes first), or
  • when the page becomes hidden (visibilitychange).

The tracker sends the final LCP with its next batch.

Examples

Marketing page with a hero image. LCP is almost always the hero <img>. If the image is below the fold or lazy-loaded, LCP ends up as a text block, usually faster.

SaaS dashboard with a skeleton loader. LCP is the skeleton container until real content paints, then it jumps to the largest data element. Watch out for falsely "fast" LCPs caused by a chunky skeleton box.

Article with embedded video. LCP is the video poster, not the article text. A lighter poster improves LCP.

How to see LCP in fastmon

The LCP page sits under Core Web Vitals → LCP. Two tiles show the LCP with its rating and the share of pageviews measured.

  • Where the time goes: server response, load delay, load duration, and render delay as one bar, against the web.dev target split.
  • History: the selected percentile against the rating zones, one line per phase, or one line per page type, beside the distribution. The maximize icon next to the share link fills the window with the chart.
  • Where the LCP is poor: page type and device, or another dimension, ranked by pageviews over 4 s. A row opens its own chart and breakdown.
  • LCP elements: each element with selector, kind, discovery path, and phases. Its detail checks HTML discovery, preload, fetchpriority, lazy loading, and browser cache, and AI prompt hands it to an assistant.

The API is POST /analytics/element-targets, with fetch_priority_high_rate, lazy_rate, and cache_rate per element.

Compare with an earlier window

Compare in the Filter panel sets a second window: the period, day, week, or month before, a window you type, or a release against the one before it. The Filter button shows it as a chip, and its × ends it. The comparison is part of the page link and works on every metric page.

With a comparison on, the summary says what changed instead of how the LCP stands. Every chart shows the second window beside the first, and Where the LCP is poor sorts by the largest regression. The API takes it as compare_to, see Compare releases.

How to improve a slow LCP

LCP splits into four phases, and Where the time goes shows each. Start with the largest.

  1. TTFB. If your time to first byte is already >1,500 ms, no amount of front-end optimization will save your LCP. Cache HTML at the edge, or render statically.
  2. Resource load delay. The LCP image isn't requested early enough. Preload it (<link rel="preload" as="image">) or move it above the fold in the HTML.
  3. Resource load duration. The LCP image is too big or served slowly. Use modern formats (AVIF/WebP), serve responsive sizes via srcset, and put it on a CDN close to your visitors.
  4. Element render delay. The browser has the bytes but is blocked by render-blocking CSS or JavaScript. Inline critical CSS, defer non-critical scripts.

More per phase: web.dev's Optimize LCP.

Common surprises

  • LCP is usually an image, not text. Tweaking fonts probably won't move your LCP at all.
  • Lazy-loading the hero delays LCP. lazy_rate above 0 on an LCP element shows it.
  • background-image counts. If your "hero" is a CSS background, the browser still measures it as LCP.

What's next

On this page