← Insights

Shopify LCP: find the element, then remove what delays it

How to find your store's largest contentful paint element, which of its four sub-parts is slow, and the theme fixes in the order that pays back first.

9 min read

Contents · 8 sections

What is the LCP element on a Shopify page?

Largest contentful paint is the time from the request until the largest visible element in the viewport has rendered. web.dev's LCP article lists what counts: img elements, image elements inside an SVG, video elements (using the poster or first frame, whichever is earlier), and elements with a background image loaded through url(). It also lists what Chrome ignores: elements at opacity: 0, elements that cover the full viewport, and low-entropy images that do not reflect the real content. The good threshold is 2.5 seconds or less, measured at the 75th percentile of page loads and segmented across mobile and desktop.

That makes the element easy to predict. On a homepage it is the first section's image, usually the hero banner. On a product page it is the first gallery image. On a collection page it is one of the first product cards, or the collection banner if there is one. If a page opens with a large heading and no image, the heading is the candidate, and its time depends on the font arriving.

Do not guess. The same article names the tools that report the element: PageSpeed Insights, Chrome DevTools, Lighthouse and WebPageTest in the lab, with the Chrome User Experience Report and Search Console's Core Web Vitals report in the field.

How do you find yours in two minutes?

Open PageSpeed Insights and test the product page, then the homepage, on the mobile tab. Two sections matter. The field data at the top, when Google has enough visits to show it, is what real visitors experienced at the 75th percentile. The diagnostics below the score name the LCP element and show a breakdown of its time.

For a local check, open the page in Chrome, open DevTools, go to the Performance panel and record a reload. The optimise LCP guide says the panel shows your local LCP beside the page's field LCP, and that the insights in a trace break LCP into its sub-parts. Throttle the CPU and network to a mid-range phone before you read anything off it. A fast laptop on office wifi will tell you the page is fine.

Write down three things: which element it is, what the score is, and which sub-part is the largest.

Which of the four sub-parts is costing the time?

web.dev splits LCP into four parts and gives the shape of a well-built page:

Sub-partShare of LCP
Time to first byteabout 40%
Resource load delayunder 10%
Resource load durationabout 40%
Element render delayunder 10%

These are guidelines, not rules. They do what a single score cannot: they say where to look. A page with a 3.4 second LCP and a large resource load delay has an image that was requested late, and no amount of compression helps that. A page with a large element render delay has an image that arrived and was hidden. A page with a long time to first byte has a problem before the theme starts, and it belongs in the third-party scripts and server-response conversation, not an image one.

The sections below take the sub-parts in the order Shopify themes most often get them wrong.

Is the hero image being lazy-loaded?

This is the most common finding and the quickest fix. Shopify's guide to never lazy-loading the LCP image calls it one of the most common and damaging performance anti-patterns in themes. When Liquid renders an img with a src, the browser's preload scanner finds the URL while it parses the HTML, before any CSS has been parsed or JavaScript has run. loading="lazy" takes that head start away. A JavaScript lazy loader such as lazysizes is worse: it replaces src with data-src, so the scanner sees nothing to fetch until the script runs.

Check it in two ways. In DevTools, inspect the LCP image and read its attributes: loading="lazy" or a data-src is the finding. Then search the theme code for the hero section's image_tag call.

The image_tag filter already does the right thing. Shopify says it sets loading="eager" for sections one to three and lazy for section four onward, and eager whenever the section index is nil, which is the case in the theme editor, in static sections and in the Section Rendering API. The trap is a theme that overrides that default with its own test:

{% if section.index <= 3 %} eager {% else %} lazy {% endif %}

Shopify points out that comparisons against nil are falsey in Liquid, so this sends the hero to the lazy branch in exactly the contexts where the built-in default would keep it eager. The fix is to write the lazy case as a positive test, section.index > 3, and let everything else fall through to eager.

Is the request starting late?

Resource load delay is the gap between the HTML arriving and the browser asking for the image. Two Shopify patterns create it.

A CSS background image. The preload scanner does not read stylesheets, so a hero set with background-image is requested only after the CSS has been found, downloaded and parsed. Shopify's guide to avoiding background images for heroes recommends an img tag positioned to fill the section instead. The metric still counts a url() background as a valid LCP element, so it measures the delay; the browser just starts late.

No priority hint. By default every image is discovered at low priority, and the browser raises the ones in the viewport only after layout. Shopify's page on marking the LCP image with fetchpriority="high" describes that gap and its fix: put the attribute on the LCP image only, one per page, combined with eager loading and never with lazy loading. The page also gives a caution worth repeating: overusing the hint can interfere with the browser's own prioritisation. The first section (section.index == 1) is the preferred place for it, so if you have moved another section above the banner, check that the hint moved with the image.

web.dev's fetch priority article explains the browser side of the same mechanism.

Is the image downloaded but hidden?

Element render delay is the last sub-part, and on Shopify it has one frequent cause: an animation. Shopify's page on not hiding the LCP image behind animations explains that Chrome excludes elements at opacity: 0 from LCP. If a theme sets a hero image to opacity: 0 and a script fades it in after DOMContentLoaded, the image can finish downloading in two seconds and LCP is still recorded when the animation finally runs.

The page lists the patterns: page transition animations in theme settings, fade-in reveal classes, hero section animations (which on their own it puts at 650 to 900 ms of wasted LCP), animate-on-scroll libraries and display: none toggled by JavaScript. It cites one store whose mobile LCP went from 3.6 s to 2.2 s after removing a hero fade-in, with a 9.4 percent increase in add-to-cart rate, and says plainly that these are case studies, not a promise.

The fastest fix needs no code. In the admin, go to Online Store, Themes, Customize, Theme settings, Animations, and turn off options such as Animate between pages or Page transitions. If an animation has to stay, Shopify's advice is a CSS @keyframes animation instead of a script-triggered transition, kept under 0.3 seconds, because a keyframe animation starts on the first render and the element becomes an LCP candidate straight away.

What if the image is simply too heavy?

Resource load duration is the part everyone works on first, and it is rarely the largest. The optimise LCP guide says the download portion tends not to be the bottleneck for most sites; the delays are. Once the three problems above are cleared, the bytes matter. Our hero image size guide covers the upload dimensions, the srcset and sizes attributes and the weight of the file a phone actually receives.

What should you fix first, and how long does it take?

Fix in this order, re-measuring after each step on the same throttling profile:

  1. Turn off page transitions and reveal animations in the theme settings. Five minutes.
  2. Remove loading="lazy" or a data-src loader from the hero and the first product image. One hour, most of it testing.
  3. Replace a CSS background hero with an img and add fetchpriority="high" to that one image. Half a day.
  4. Only then work on file weight and the server response.

Do the first three and re-test the next morning, because the field data in PageSpeed Insights moves over weeks, not minutes; the lab figures show the change at once. Layout stability is the sister metric and has its own threshold; our cumulative layout shift guide covers it, and the slow store checklist shows where LCP sits among the other causes. If you would rather have the LCP element, its sub-part breakdown and the theme lines to change identified on your own store, that is part of what our Store Teardown measures.

Next step

Own your growth.Start with the teardown.

Read it, then decide whether you want us to fix what it finds.