Finding the actual LCP element and fixing the phase that is really slow
Largest Contentful Paint is widely regarded as the most important of the three Core Web Vitals for perceived load speed, yet in practice it often gets approached wrong, with teams generically trying to make the entire page faster. The first necessary step is identifying the actual LCP element on a page, which is often not the element you would intuitively expect. The second step is breaking the LCP time down into its four phases, TTFB, Load Delay, Load Time, and Render Delay, and optimizing each phase specifically and individually, instead of chasing a diffuse improvement of the total time.
Table of Contents
- 1. LCP as the primary load-time metric of the Core Web Vitals
- 2. Determining the LCP element for a given page
- 3. Why the LCP element is often not the obvious one
- 4. An overview of the four phases of LCP time
- 5. Phase one: tackling TTFB specifically
- 6. Phase two: tackling Load Delay specifically
- 7. Phase three: tackling Load Time specifically
- 8. Phase four: tackling Render Delay specifically
- 9. Why phase-based diagnosis beats generic optimization
- 10. Summary
- 11. FAQ
1. LCP as the primary load-time metric of the Core Web Vitals
Largest Contentful Paint measures the point in time when the largest element rendered within the initially visible viewport finishes displaying, usually a hero image, a large heading, or a block-level text element. This metric correlates strongly with the subjective impression of load speed, since it captures exactly the moment a page's main content becomes visible and therefore usable to the visitor, unlike earlier metrics such as First Paint, which could also be triggered by small elements irrelevant to the visitor.
Google defines an LCP score of 2.5 seconds or below as good, with that threshold measured at the 75th percentile of all page views, not the median. That choice means the slower, often mobile or poorer-network page views have to be explicitly accounted for, and an optimization that only improves the average case may barely move the actually measured LCP score at all.
2. Determining the LCP element for a given page
Which element actually counts as the LCP element on a given page cannot be reliably guessed, it has to be read directly from the browser via the PerformanceObserver API using the largest-contentful-paint entry type. This observer fires for every candidate that becomes the largest visible element seen so far, and provides a reference to the concrete DOM element through the element property, letting you determine the actual LCP candidate programmatically instead of assuming it from a visual impression.
In production it is worth capturing this continuously through Real User Monitoring rather than checking it once in a lab, since the LCP element can differ from view to view depending on viewport size, loaded A/B test variants, or personalized content. The example below shows a minimal observer that logs the element and the time value for every new LCP candidate.
// Determine the LCP element and timing via PerformanceObserver
const observer = new PerformanceObserver((entryList) => {
const entries = entryList.getEntries();
const latestEntry = entries[entries.length - 1];
console.log('LCP candidate:', latestEntry.element);
console.log('Time to this candidate:', latestEntry.startTime);
console.log('Resource URL (if image):', latestEntry.url || 'no image');
});
observer.observe({ type: 'largest-contentful-paint', buffered: true });
// Finalize the value on the first user interaction or visibility change
['keydown', 'click', 'visibilitychange'].forEach((eventName) => {
addEventListener(eventName, () => observer.takeRecords(), { once: true, capture: true });
});
3. Why the LCP element is often not the obvious one
A common misconception is assuming the LCP element is automatically the large hero image at the top of the page, when in many real cases a different element takes that role. On a blog article page, for instance, a long, multi-line heading block can occupy more screen area than a smaller header image, which makes the text, not the image, the LCP element and calls for different optimization measures than pure image optimization.
It gets even more surprising on pages with dynamically loaded content, for example a carousel that initially shows a small placeholder image on first render and only swaps in the actual, larger image after JavaScript has loaded. In this case the LCP timestamp can incorrectly land on the small placeholder image, even though the visitor perceives the larger image as the actually relevant content, which shows how important programmatic verification through the PerformanceObserver is compared to a purely visual guess.
4. An overview of the four phases of LCP time
Once the LCP element is known, the total LCP time can be broken down into four clearly distinct phases, each influenced by different technical factors: Time to First Byte, the time until the first server response, Load Delay, the time between TTFB and the start of loading the LCP resource, Load Time, the actual download duration of the resource, and Render Delay, the time between the finished download and the actual rendering on screen.
This breakdown is valuable precisely because each phase gets improved by completely different measures, and a generic goal like making the page faster without knowing the dominant phase almost always targets the wrong spot. A team that puts significant effort into image compression while the Load Delay phase is actually caused by a blocking script barely moves the LCP score, even though objectively valuable work got done.
5. Phase one: tackling TTFB specifically
The TTFB phase is primarily determined by server response time, network latency, and the distance between the visitor and the server, making it the one phase out of the four that is barely influenced by frontend measures, and instead almost entirely by backend and infrastructure decisions. A slow database query, an overloaded application server, or the absence of an edge cache for frequently requested pages fall directly into this phase and can be addressed independently of every other LCP-related measure.
A CDN with edge caching for largely static pages, optimizing slow database queries, and the geographic proximity of the server to the visitor are the most effective levers against a slow TTFB phase. For dynamically generated, personalized pages where full caching is not possible, streaming SSR additionally helps, since the shell can already be sent while personalized data is still loading in the background, lowering the effectively perceived TTFB for the LCP element.
6. Phase two: tackling Load Delay specifically
Load Delay occurs when unnecessary time passes between the HTML document arriving and the actual start of downloading the LCP resource, frequently caused by render-blocking scripts or stylesheets that must load before the LCP resource, or by the resource being discovered late because it only gets inserted into the DOM via JavaScript instead of being present directly in the initial HTML.
The most effective measures against Load Delay are referencing the LCP resource directly and statically in the HTML so the preload scanner discovers it immediately, and avoiding or at least shrinking render-blocking resources that load before the LCP resource. A targeted fetchpriority="high" on the LCP element additionally helps by favoring it over competing resources within the already-early discovery.
7. Phase three: tackling Load Time specifically
Load Time refers to the pure download duration of the LCP resource itself once the request has started, and is primarily determined by file size, compression, and connection bandwidth. For image LCP elements this concretely means using modern formats like AVIF or WebP with reasonable compression, delivering the correctly sized image for the actual viewport via srcset, and serving the resource through a CDN with good geographic coverage.
For text LCP elements, say a large heading, the Load Time phase usually barely registers, since text itself needs very few bytes, unless rendering the text indirectly depends on a still-loading web font. In that case the actual bottleneck effectively shifts into the Load Time phase of the font file, which is why optimizing font loading, for example via preload and a font subset reduced to only the actually used characters, represents the biggest lever here.
8. Phase four: tackling Render Delay specifically
Render Delay is the time between the LCP resource finishing its download and actually appearing on screen, and is frequently underestimated even though it can account for a substantial share of the total time in client-rendered applications. Typical causes include a long, blocking JavaScript task on the main thread that delays actual rendering even though the resource itself has long since downloaded, or an inefficient CSS cascade that only stabilizes the final layout after several recalculations.
The most effective measures against Render Delay are breaking long JavaScript tasks into smaller units so the main thread does not stay blocked over extended periods, and delivering critical CSS for the initially visible viewport inline instead of pulling it from a still-to-be-loaded external file. In React or similar frameworks, it additionally helps to avoid placing the LCP element behind a Suspense boundary with artificial delay when it is critical for the first visible content.
9. Why phase-based diagnosis beats generic optimization
The decisive advantage of phase-based diagnosis over the generic question of making the page faster is that optimization effort can be focused specifically on the actually dominant phase, instead of getting spread evenly across all four phases, where it shows little effect in three out of four cases. Tools like the Chrome DevTools performance panel or specialized web vitals libraries now display the four phases explicitly as separate time segments, making it possible to identify the dominant phase within minutes.
In practice a recurring process works well: after every significant change to a page, the LCP phase distribution gets measured again to check whether the dominant phase has shifted, for instance because a previously good TTFB suddenly became the largest phase due to new, heavier backend logic. This continuous, phase-aware monitoring prevents optimization effort from being invested in a phase that used to matter but is no longer the actual cause of the LCP time.
| Phase | What it measures | Most common cause | Most effective fix |
|---|---|---|---|
| TTFB | Time until the first server response | Slow backend logic, missing edge cache | CDN caching, database optimization, streaming SSR |
| Load Delay | Time until the resource download starts | Render-blocking scripts, late discovery | Static HTML reference, fetchpriority="high" |
| Load Time | Pure download duration of the resource | Large file size, missing compression | Modern image formats, srcset, CDN with good coverage |
| Render Delay | Time between download finishing and rendering | Blocking JavaScript task, late CSS | Task splitting, inline critical CSS |
Mironsoft
Web performance, Core Web Vitals, and load time optimization
Load times that don't make users bounce before the page is even visible?
We review existing websites for slow Core Web Vitals, bloated JavaScript bundles, and unnecessary render blockers, then build a performance foundation that stays measurable instead of just looking good once.
Performance Audit
Systematically measuring and fixing Core Web Vitals, load waterfall, and render blockers.
Bundle Optimization
Specifically reducing JavaScript and CSS bundle size and improving code splitting.
Monitoring Setup
Establishing continuous performance monitoring instead of a one-time snapshot.
10. Summary
Identifying and Optimizing LCP: The Key Points
Core idea
LCP optimization starts with programmatically identifying the actual LCP element, not a visual guess.
Four phases
TTFB, Load Delay, Load Time, and Render Delay each get improved by completely different measures.
Common mistake
Optimizing image compression while the real delay sits in a different, undiagnosed phase.
Approach
Remeasure the phase distribution after every significant change instead of relying on a one-time diagnosis.