Core Web Vitals

How to improve Largest Contentful Paint by fixing the slowest LCP stage

The largest image is not always the problem; the delay before it starts loading can matter more.

A browser viewport highlights its largest content block, with a thin line marking progress toward rendering.

Improve Largest Contentful Paint by identifying the element that determines LCP and measuring what delays its appearance. For an image, separate the wait for HTML, the delay before its request starts, its download and the remaining wait before rendering. Then fix the stage that is actually slow instead of applying every image optimization at once.

LCP is good at 2.5 seconds or less at the 75th percentile. That target describes an outcome for visitors. It does not tell you whether the cause is a slow server, a late-discovered photograph or a page that hides already-downloaded content until JavaScript finishes.

Find the element before changing its delivery

Record a page load in Chrome DevTools at the viewport size you need to investigate. Inspect the LCP event and its associated element. Compare it with the page visible in the recording, because the browser can identify a later, larger candidate as loading progresses.

Eligible candidates include images and text blocks, with additional rules for image backgrounds and video content. LCP is not simply the largest DOM node or the last network request. A large container full of empty space does not become meaningful content just because its dimensions are large.

Repeat the check on relevant templates and device sizes. A headline can determine mobile LCP while a product image determines desktop LCP. An experiment or consent state can also change what is visible. Record the conditions alongside the element so the next test examines the same scenario.

In a project that bundles the web-vitals attribution build, this diagnostic module logs the image URL and stage timings when available.

js
import { onLCP } from 'web-vitals/attribution';

onLCP(({ value, attribution }) => {
  console.table({
    lcp: value,
    resource: attribution.url ?? 'Text or no image resource',
    ttfb: attribution.timeToFirstByte,
    loadDelay: attribution.resourceLoadDelay,
    loadDuration: attribution.resourceLoadDuration,
    renderDelay: attribution.elementRenderDelay
  });
});

This is an observation aid, not a complete monitoring service. It requires an installed compatible package and a build setup that resolves its imports. Field collection additionally needs a carefully designed endpoint and aggregation. Check the library version and its attribution interface when incorporating the example.

Use the four-stage breakdown to choose the first fix

Google's LCP optimization guide separates image-based LCP into stages that correspond to different kinds of work. For text-based LCP there may be no image-resource download, so do not invent one to fit the model.

Stage Diagnostic question Likely investigation
Time to First Byte When does the browser receive HTML? Redirects, origin work and caching
Resource load delay When can the image request begin? Initial markup, CSS discovery and priority
Resource load duration How long does the image transfer take? Dimensions, encoding and delivery
Element render delay Why is downloaded content still invisible? CSS, fonts, main-thread work and hidden states

A useful change shortens the complete route to visible content. Suppose an image downloads sooner but waits behind the same long rendering task. The download stage improves while the render-delay stage grows, leaving the final LCP little changed. That is a real diagnosis, not evidence that image compression never helps.

Keep the original trace. The before-and-after comparison should show which stage changed and whether the intended element still determines LCP. If another element becomes the candidate, investigate that transition rather than comparing unrelated resources without explanation.

Reduce the time before HTML arrives

The browser cannot discover ordinary document resources before it receives enough of the document to identify them. Follow the navigation request through redirects, connection setup and the final response. A chain of redirects can delay discovery even when the application itself is quick.

Compare cached and uncached page responses. A warm homepage may conceal slow application execution on less popular URLs. Check whether a CDN caches the HTML or only its static assets, and whether cookies unexpectedly bypass public caching.

Do not make personalized pages public merely to improve a timing. Cache behavior must preserve sessions, access controls and content correctness. The server-response-time guide explains how to separate these concerns and measure the work that a cache hit avoids.

Server-side rendering also needs context. Returning useful markup can reduce client-side discovery work, but an expensive rendering pipeline can increase TTFB. Measure both the response and the resulting paint. A fast empty shell is not the objective.

Make the important image discoverable immediately

An image URL in the initial HTML is available to the browser's resource discovery machinery. An image created only after JavaScript runs inherits that dependency. A CSS background image can require the stylesheet to arrive and be processed before its URL is discovered.

Prefer an ordinary image element for meaningful content when it fits the design and semantics. Give it accurate alternative text and dimensions. Do not add loading="lazy" to the image that should appear in the first viewport simply because lazy loading is enabled for other media.

The following example assumes an image displayed at up to 960 CSS pixels, with a narrower mobile layout. Its files are illustrative project assets and must be supplied by your build.

html
<img
  src="/images/guide-960.webp"
  srcset="/images/guide-640.webp 640w,
          /images/guide-960.webp 960w,
          /images/guide-1600.webp 1600w"
  sizes="(max-width: 960px) 100vw, 960px"
  width="1600"
  height="900"
  fetchpriority="high"
  alt="A browser displaying a highlighted content panel"
>

The browser uses sizes, the candidate widths and device characteristics to choose a resource. The sizes value must match the actual layout; it does not set the image's CSS width. If the image occupies half a desktop column, describing it as full viewport width can cause an unnecessarily large download.

fetchpriority="high" tells the browser that this request is particularly important. It does not make a hidden resource discoverable, and assigning it to many competing images weakens the prioritization you intended. Start with the measured LCP candidate and inspect the waterfall afterward.

Preload only when earlier discovery solves a real delay

Preload is useful for a critical resource that would otherwise be discovered late. It is not an instruction to fetch every visible asset before the browser can make its own scheduling decisions.

For a genuinely critical CSS background, an image preload can start the request before the stylesheet reveals it. This pair uses the same URL so the intended request can be reused.

html
<link rel="preload" as="image" href="/images/banner.webp"
      fetchpriority="high">
css
.banner {
  min-height: 18rem;
  background-image: url('/images/banner.webp');
  background-size: cover;
  background-position: center;
}

The dimensions in this layout example are design choices, not performance thresholds. Use a meaningful image element instead when the picture conveys information that should have alternative text.

Responsive images need matching preload selection if you preload them. A fixed preload URL can waste bandwidth when the image element selects a different candidate. Check request URLs, resource types and credentials behavior rather than assuming that two references to similar images are one transfer.

After adding a hint, check whether a useful request started earlier and whether other critical work was displaced. An unused-preload warning is a reason to inspect the implementation, not merely something to suppress.

Reduce image bytes without degrading the content

Once discovery is timely, inspect the selected image dimensions and transfer size. Export candidates appropriate to the rendered slot and intended pixel density. A high-density display may legitimately need more image pixels than the CSS width, so the rule is not simply to make both numbers identical.

Compare suitable formats and compression settings on the actual image. AVIF or WebP can be useful options, but content, quality requirements and encoding choices affect the outcome. Fine text, diagrams and photographs do not necessarily respond to compression in the same way.

Inspect the result at its displayed size. Blurred product details, damaged lettering or visible artifacts are not acceptable merely because the file is smaller. Keep the original source and make export settings reproducible so subsequent editorial changes do not undo the optimization.

An image CDN or CMS transformation pipeline can automate variants, but verify the emitted markup and selected request. A feature labelled responsive does not prove that the sizes attribute matches your theme. Follow the image optimization guide for format and responsive-markup decisions.

Use the image savings calculator to compare byte changes. It estimates transfer savings from the values you enter, not the number of milliseconds your LCP will improve. Parallel loading, caching and the other stages still matter.

Investigate the gap between download and paint

If the image has arrived but appears much later, inspect what keeps it from rendering. Stylesheets may still be needed to establish the page's appearance. JavaScript may occupy the main thread. A component may remain hidden until an animation, initialization callback or client-rendered state completes.

Remove unnecessary visibility dependencies. An important image should not wait for unrelated carousel logic if the first slide can be represented in ordinary markup. Check whether a loading overlay covers content that is already ready and whether an entrance animation delays the metric without helping the visitor.

Inspect render-blocking CSS carefully. The goal is not to delete every stylesheet or defer all styling. First-view content needs correct styles to avoid flashes and movement. Identify unused or noncritical assets, then preserve the rules required for the actual first viewport.

Main-thread work can delay rendering even after network work finishes. Look for large scripts, hydration and synchronous initialization around the relevant point in the recording. The render-blocking resource guide distinguishes discovery and execution dependencies that are easily confused.

For a text-based LCP, investigate fonts and text visibility. A font request can influence when the heading appears, while fallback metrics can affect layout. Do not assume that preloading every font is the answer: it can compete with the resources the first viewport needs more urgently.

Check the mobile and content variants you actually serve

Test a long heading as well as a short one. Test an article with a hero image and one without. Include the real consent state, advertising configuration and localization where these change the visible layout. Shared code can produce different LCP candidates depending on content.

A narrow viewport may crop or hide the desktop hero, while the browser still downloads it because the markup and styling disagree. Conversely, a mobile-specific asset can be requested too late if a script chooses it after startup. Inspect actual network requests, not only what the final page shows.

For localized pages, font coverage and line wrapping can change both the candidate and its rendering dependencies. Keep the same diagnostic process across editions rather than assuming an English-page improvement proves every language improved.

Validate one hypothesis with a comparable recording

Write the hypothesis before editing: for example, the LCP image is discovered late because it is inserted by a component after initialization. Then make the smallest change that tests that explanation and record the same scenario again.

Compare the resource start, its transfer completion, the paint and the overall LCP. Repeat under the same viewport, throttling and cache conditions. Keep failed runs and errors visible; a page that stopped loading an important feature can look faster for the wrong reason.

After deployment, inspect real-user data over its collection window. Field LCP can differ from your lab scenario because visitor hardware, connections, geography and navigation behavior differ. A lab improvement is useful evidence, but it is not a substitute for the field result.

Make the result easy to maintain

Record which element matters, how it is discovered and which optimization is intentional. A short implementation note can prevent a later image plugin from reintroducing lazy loading or a redesign from changing the slot without updating sizes.

Keep the case in your review routine: one representative page, the intended image candidate, the expected discovery path and a saved trace. Use the Core Web Vitals reference guides when another metric becomes the limiting factor. The next task should come from the next measured delay, not from another generic optimization switch.

Related guides