How a 768 KB Preload Made a Storefront Take 7.2s to Paint
A Small Batch Brine teardown: Lighthouse mobile 74 with a 7.2s LCP, one root cause, and the fixes that took it to 97 (LCP 2.0s). Dated and reproducible.
Answer in 30 seconds
Lighthouse mobile went 74 (LCP 7.2s) to 97 (LCP 2.0s) after removing a 768 KB hero image the layout preloaded but never rendered, right-sizing the images actually shown, and letting the browser describe the hero's dimensions up front. The regression was one import, not a slow framework.
This is a real teardown of a real build: Small Batch Brine, one of my self-initiated concept builds: a storefront for a local craft food brand with WhatsApp-based ordering. No client affiliation, no invented metrics. The numbers below are Lighthouse mobile, median of three runs, and they are the same numbers the build breakdown publishes.
Starting score: 74 · LCP 7.2s. Ending score: 97 · LCP 2.0s.
The fix was one bad import. Here is how I found it, and why this exact bug is more common than any "slow framework" story.
What LCP Actually Measures
Largest Contentful Paint is the moment your biggest above-the-fold element (usually a hero image or headline) has actually painted. Google's "good" threshold is 2.5s. At 7.2s, a visitor on a mid-range phone stares at a blank page for seven seconds, and large numbers of them leave before seeing anything.
So when LCP is terrible, you are not looking for "a slow site". You are looking for the one thing blocking that first paint.
The Bug: An Image Nobody Saw
The layout preloaded a 768 KB PNG: a hero asset left over from an earlier design that the page no longer rendered.
Every page load, the browser:
- Hit the preload tag, saw an image marked as critical, and started downloading 768 KB immediately.
- Competed for bandwidth and connection slots with the CSS and JS chunks that actually gate first paint.
- Rendered nothing with the image anyway, because the current design never placed it on the page.
So the page was paying full price for an asset it did not use, and the real hero was queued behind it. On Lighthouse's mobile profile: 150ms RTT, 1.6 Mbps, 4× CPU throttling: that queue is the difference between 2s and 7s.
You cannot see this by looking at the page. You see it in DevTools → Network: a phantom request in the first 100ms with fetchpriority=high and no corresponding element, and a waterfall where the chunks that build the page start after it.
The Fixes, In Order of Impact
1. Delete the preload (and the file). A preload is a promise that says "this is critical". When the element is gone, the promise is a debt. One deleted import removed 768 KB from the critical path.
2. Serve the hero at the size it renders. The displayed hero image was a 1600px-wide source in a box that never got wider than ~800 CSS pixels. Right-sizing to 800px at quality 80 cut the bytes roughly in half with no visible difference on a DPR-2 phone.
3. Let the browser reserve the hero's space. Explicit width/height on the hero image (and on the product grid below it) means the browser lays out the page in one pass instead of relayouting when each image lands. Layout stability is part of what earns a repeat visit.
After those three, the same build scored 97 · LCP 2.0s.
The Second Finding: The Connection Changes the Number
Weeks later I re-measured the same build under two profiles and published both rows:
| Profile | Score | LCP |
|---|---|---|
| Lighthouse mobile preset: 150ms RTT / 1.6 Mbps / 4× CPU | 99 | 2.0s |
| Measured connection: 16ms RTT / 4 Mbps / 4× CPU | 100 | 0.7s |
Same code, same day, 3× different LCP. That is not a contradiction: it is the same finding the sprint publishes everywhere: a performance number without its connection profile is not a measurement, it is a mood. If a developer shows you "0.8s" with no profile named, ask what it was measured on. The honest answer is on this page.
What This Means If Your Site Is Slow
The pattern is almost always the same three suspects, in this order:
- Something enormous loads before your first paint: a hero video, an unsized image, a preloaded font you don't render with, or a tracking script.
- Images are served at 3× the size they display.
- The first paint waits on client JavaScript that could have been HTML.
None of those requires a rewrite. They require someone to open the network tab and read the waterfall: which is exactly what the first session of the 5-day sprint or a speed quick fix does, with the before/after numbers written down either way.
Want to know which of the three your site has? Run the free instant grader: it flags the biggest issue in about 30 seconds, and it will tell you your site is fine when it is fine. The build in this post is public; the numbers are dated in the breakdown; the measurement method is written under the sprint's scope. That is the standard every number on this site is held to.
Work with me
Need a site that loads fast and sells?
Seven live builds with dated measurements and fixed prices published up front. Read the breakdowns: or send me the rough version of your problem.
Related reads
From 5.9s to 3.8s: Why a Hidden Hero Makes Everything Slow
A Through Tenon teardown: Lighthouse mobile 75 with a 5.9s LCP caused by an entrance animation, and the fixes that recovered two seconds.
Your performance score is a sales number, not a report card
Core Web Vitals, why Google penalizes slow websites, and the engineering behind a near-perfect Lighthouse score.
What one churned customer actually costs you
A SaaS ROI method for founders who think in MRR, churn and onboarding conversion. Compare one lost customer to the cost of fixing the leak.