<Ghayas/>

What actually fixed LCP on a slow storefront

/3 min read/Ghayas Ud Din
Performance metrics displayed on a laptop screen

A store came to me with a Lighthouse score of 31 and a marketing agency quoting five figures to “optimise” it. Field LCP was 4.8 seconds at the 75th percentile. Google’s threshold is 2.5.

We got it to 1.9 seconds. Here is what moved the number, in order, and what did not.

1. The hero image was not preloaded (−1.4s)

By far the biggest win, and the least interesting. The LCP element was the hero image, discovered only after the browser parsed CSS, resolved the responsive srcset and built the layout. It was starting its download roughly 900ms into the page load.

Preloading it with a matching imagesrcset moved the request into the initial burst:

<link rel="preload" as="image"
      href="/hero-800.webp"
      imagesrcset="/hero-800.webp 800w, /hero-1600.webp 1600w"
      imagesizes="100vw" fetchpriority="high">

The imagesrcset attribute matters. Preload the wrong variant and the browser downloads two images and uses the slower one.

2. Render-blocking app CSS (−0.7s)

One 340KB stylesheet, of which the above-the-fold content used maybe 8KB. It blocked rendering entirely.

I did not do full critical-CSS extraction — it is fragile and it rots the moment someone edits a section. I inlined the header and hero rules by hand, about 6KB, and loaded the rest with a media="print" swap. Crude, stable, still working eight months later.

3. Fonts blocking text paint (−0.3s)

Two families, five weights, all loaded from a third-party host. Self-hosting them removed a DNS lookup, a TLS handshake and a connection to a domain the browser had no reason to trust.

font-display: swap was already set, which is why this was worth less than people claim. If your fonts block and you have no swap, this is a much bigger number.

4. Deferring the third-party tag pile (−0.2s on LCP, −1.1s on INP)

Eleven third-party scripts. A chat widget, two heatmap tools, three analytics vendors, a review widget, a currency converter and an abandoned A/B testing tool nobody had removed.

The A/B tool alone was 180KB and had not run an experiment in fourteen months. Deleting dead vendors is the highest-leverage performance work available and it requires no engineering skill at all — just someone willing to ask “does anyone still use this?”

LCP barely moved, because these were not blocking the hero. Interaction latency improved enormously. Users noticed that far more than the LCP number.

What did nothing measurable

Switching to WebP. Already served by the CDN with content negotiation. Re-encoding the source assets changed nothing.

Lazy-loading everything. Someone had added loading="lazy" to all images including the hero, which actively delayed LCP. Removing it from above-the-fold images was worth more than adding it anywhere else.

Reducing DOM size. A 2,100-node page. Advice says keep it under 1,500. Cutting it to 1,400 changed LCP by about 20ms, comfortably inside the noise.

A CDN change. They were already on a decent one. The proposal to migrate would have cost weeks and improved TTFB by maybe 15ms.

How to know which is which

Lighthouse is a lab tool. It will hand you a list of twenty “opportunities” ranked by theoretical savings and most of them will not apply to your traffic.

Field data decides. Pull Chrome UX Report data for your own origin, find the actual LCP element for the pages that get traffic, and fix that. On this store the LCP element on mobile was not the hero at all — it was a promotional banner above it, which nobody had looked at because it did not appear in the desktop screenshot.

Measure first. Nearly everything else is folklore.

core-web-vitalslcpperformanceshopify

Keep reading