Ecommerce LCP (Largest Contentful Paint) measures how long it takes for the biggest thing on screen, usually a hero image, the main product photo or a large heading, to appear. Google considers 2.5 seconds or less good, measured at the 75th percentile of real visits. On the stores we audit, LCP goes wrong in the same few places: the hero image is discovered late or lazy-loaded, third-party apps block or hide the page, fonts delay text, and the problem is measured on the homepage while it actually lives on product and category templates.
LCP in four parts
Every LCP time can be split into four phases, as described in web.dev’s guide to optimizing LCP:
| Phase | What it is | Typical ecommerce cause when it is long |
|---|---|---|
| Time to first byte | The server’s response time | Uncached pages, slow platform or plugin work, no CDN |
| Resource load delay | Time before the browser starts loading the LCP image | Image set in CSS or JavaScript, lazy-loaded, or behind a carousel script |
| Resource load time | Time to download the image | Oversized files, wrong format, no responsive sizes |
| Element render delay | Time between having everything and showing it | Render-blocking scripts, anti-flicker snippets, hidden content, fonts |
Knowing which phase is long tells you what to fix. A hero image compression project will not help if the image is ready in 400 milliseconds and the page is hidden by an A/B testing script for two seconds.
Where it goes wrong
Hero images discovered late
The browser can only start loading an image once it knows about it. Images set as CSS backgrounds, inserted by a slider script, or chosen by JavaScript based on screen size are found late. Put the LCP image in the HTML as an <img> with srcset and sizes, and tell the browser it matters with fetchpriority="high".
The LCP image is lazy-loaded
Lazy-loading everything is a common “optimisation” that makes LCP worse: the most important image waits until layout is known. Lazy-load images below the fold; load the hero and the main product image eagerly. Themes and plugins often apply lazy-loading globally, so check the actual HTML.
Carousels and hero sliders
A slider usually means several large images, a script that must run before the first slide is shown, and sometimes a fade-in animation. If you keep a slider, make the first slide a normal eager image in the HTML and let the script take over afterwards.
Oversized images
We still find 3,000-pixel-wide hero images served to phones. Serve WebP or AVIF, generate sizes that match the layout, and let sizes pick the right one. Most platforms have an image CDN that does this if the theme asks for it correctly.
Third-party apps that block or hide the page
Review widgets, personalisation tools, chat, popups and tag managers add scripts that compete for the network and the main thread. The worst are A/B testing tools with anti-flicker snippets, which deliberately hide the page until the testing script has loaded. If that script is slow, LCP is slow on every page it runs on. Audit what loads before the first paint and ask whether each item needs to be there.
Fonts that hold back text
When the LCP element is text (common on product and article pages), web fonts matter. Use font-display: swap so text shows immediately in a fallback font, preload the one or two font files used above the fold, self-host rather than loading fonts from a third-party domain, and use a size-adjusted fallback so the swap does not shift the layout. web.dev’s font best practices cover the details.
Loading states that hide finished content
This one surprised us on our own site. While tuning it recently, we found that a route-level loading skeleton (the grey placeholder blocks many modern frameworks show while a page loads) was being served even for pages that were already fully built, with the real content revealed by a script afterwards. On a slow phone that reveal waited for the main thread, adding well over a second to LCP. Removing it for cached pages cut LCP by roughly a second in our throttled tests. If your theme or framework uses loading states, check what the HTML contains before scripts run.
Slow server responses
If TTFB is already long, everything else starts late. Full-page caching for anonymous visitors, a CDN, and avoiding slow work on each request are the usual fixes; on WooCommerce our performance checklist covers the server side.
Measure per template, not per site
Most speed reports test the homepage. Most revenue comes through product and category pages, which have different LCP elements and different problems. Measure each template separately:
- Field data first. Search Console’s Core Web Vitals report groups similar URLs, which usually maps to templates. The Chrome UX Report has URL-level data for pages with enough traffic.
- Lab tests per template to diagnose: pick a representative product, category, cart and content page, and test each on a throttled mobile profile.
- Know which element is the LCP on each template. It changes with layout: the hero on the homepage, the main photo on products, often a heading or the first product image on categories.
A single lab score is noisy. Run tests several times and compare medians, and trust field data over lab data when they disagree.
A worked example: one product page
A pattern we see often: a product page with a poor LCP on mobile, where the team has already compressed every image. Breaking the LCP into phases showed a short time to first byte and a fast image download, but a long resource load delay and a long render delay.
- The main product image was lazy-loaded by the theme’s global setting, so the browser did not request it until layout was complete. Making it eager with high fetch priority moved the request to the start of the page load.
- A personalisation script with an anti-flicker snippet hid the page until it loaded. Giving the snippet a short timeout, and then moving the tool to pages where it was actually used, removed most of the render delay.
- A reviews widget loaded its full script before the first paint. Deferring it until after the main content had no visible cost to shoppers.
None of these involved new infrastructure or a redesign. They were found by looking at which phase was long rather than by applying a generic speed checklist.
The LCP fix list
- LCP image is an
<img>in the initial HTML, not a CSS background or script-inserted. - LCP image is not lazy-loaded and has
fetchpriority="high". - Responsive sizes and modern formats are served; width and height are set.
- No anti-flicker or hiding snippet runs before the first paint, or it has a short timeout.
- Third-party scripts that are not needed for the first view are deferred or loaded on interaction.
- Above-the-fold fonts are self-hosted, preloaded and use
font-display: swap. - Cached pages are delivered complete in the HTML, without a loading state in front of them.
- Server response time is measured and cached pages are served from a CDN.
- Each main template is measured separately in field and lab data.
Platform notes
On Shopify, much of the server side is handled by the platform, and most LCP problems come from the theme and apps; our template-by-template Core Web Vitals fix list for Shopify covers what you control there. On WooCommerce, the server side is your responsibility too. On headless builds, check that pages are rendered on the server or pre-built, not assembled in the browser.
Our speed optimization work starts with exactly this breakdown: which template, which element, which phase. If your store is on Shopify and the theme itself is the problem, our Shopify development team can rebuild the affected sections without a full redesign.

