Largest Contentful Paint is usually blamed on images, but on React storefronts the slowest element is often a hero image delayed by JavaScript, a late-loading font, or a client-side data fetch. Start by identifying the actual LCP element in the field, not by guessing from a local score.
Start with the element, not the score
Open a performance trace on a throttled mobile profile and find the element marked as LCP. Check when its request starts, when it finishes, and what blocked it. If the image is discovered late, no amount of compression will fix the delay.
Make the hero discoverable immediately
- Server-render the hero markup so the browser knows about the image in the first response.
- Add a preload for the correct responsive image source, not every variant.
- Use fetchPriority high only on the one image that is the LCP candidate.
- Avoid lazy-loading the above-the-fold image. Lazy-load the rest.
Give images the right dimensions and format
Serve AVIF or WebP with a srcset that matches real layout widths. Set width and height to prevent layout shift, and use sizes so mobile does not download a desktop asset. A beautiful 2400px hero is wasted on a 390px screen.
Reduce what loads before the hero
Third-party tags, carousel libraries, and large client providers all compete for the same connection. If the hero depends on a client-side fetch, move the data requirement to the server or render a useful static state first. For fonts, self-host, subset, and use font-display swap.
Measure in the field, then re-run lab tests
Local Lighthouse runs are useful for catching regressions, but CrUX and real-user monitoring tell you what customers experience. Track LCP by page type and device, and compare before and after over a meaningful window. One fast test is not a result.
The fastest hero is the one the browser can find in the first response, with no JavaScript in the way.