82% of Shopify Stores Lazy-Load Their LCP Image — Are You One of Them?
Lazy loading is a valuable performance technique — for images below the fold. Applied to the hero image, it is actively harmful: the browser intentionally delays fetching the image until it determines whether it is in the viewport, adding 1-3 seconds to LCP on most devices. Industry data from Shopify's own performance team suggests the majority of custom Shopify themes have loading='lazy' on their hero image. This guide shows you how to audit your theme and fix the issue in minutes.
Why lazy loading the LCP image destroys performance
When a browser encounters loading='lazy' on an image, it defers the fetch until the image is 'near the viewport' — a distance threshold that varies by browser but is typically calculated after layout. On a page load, layout hasn't happened yet when the browser first parses the HTML. This creates a dependency chain: parse HTML → build layout → determine image is in viewport → begin fetch. Without lazy loading, the image fetch begins immediately during HTML parsing — potentially seconds earlier.
How to audit your theme for this issue
Method 1: View page source in Chrome (Ctrl+U / Cmd+U), search for loading="lazy" and check if any hero or banner images have this attribute. Method 2: Chrome DevTools > Network tab > filter Images > look for your hero image download starting late in the waterfall. Method 3: PageSpeed Insights at pagespeed.web.dev — the LCP element is identified and a 'lazy-loaded LCP image' warning appears in the Opportunities section if this issue is present.
Using section.index to assign correct loading attributes
The correct pattern in Shopify Liquid uses section.index to determine whether a section is the first on the page: {% assign fetch_priority = 'auto' %}{% assign image_loading = 'lazy' %}{% if section.index == 1 %}{% assign fetch_priority = 'high' %}{% assign image_loading = 'eager' %}{% endif %}{{ image | image_url: width: 1500 | image_tag: loading: image_loading, fetchpriority: fetch_priority }}. This automatically applies eager+high to the first section and lazy to all subsequent ones, regardless of how merchants arrange sections.
What about images inside conditional blocks
If your hero image is conditionally rendered (inside {% if section.settings.show_image %} or similar), the section.index logic still applies. The key rule: any image that is likely to be in the viewport on initial page load must have loading='eager', never loading='lazy'. When in doubt, use eager — the performance cost of eagerly loading an above-fold image is zero (it would be loaded anyway), while lazy loading adds latency.
The fix: before and after
// CODE_COMPARISON
Frequently asked questions
- What is the loading attribute default when I omit it entirely?
When no loading attribute is specified, the browser uses 'eager' by default for all images. This means an image without a loading attribute downloads immediately. However, explicitly setting loading='eager' on the LCP image and loading='lazy' on all other images is better practice — it makes intent clear and prevents future developers from accidentally adding lazy loading to the hero.
- Should I use loading='eager' on every above-fold image?
Use loading='eager' on images that are visible in the viewport on initial page load without scrolling. For most Shopify store layouts, this is only the hero image. Navigation logos are typically small SVGs or inline images that don't benefit from explicit eager loading. For any image that is sometimes above the fold and sometimes not (depending on viewport size), prefer eager — the cost of eagerly loading an image that is off-screen is one unnecessary HTTP request; the cost of lazy loading an LCP image is 1-3 seconds of LCP delay.
- How do I check if my fix actually improved LCP?
Run PageSpeed Insights (pagespeed.web.dev) on your homepage before and after the change. The LCP metric is shown prominently. For a more accurate field data measurement, enable CrUX data in Search Console and check the Core Web Vitals report 2-4 weeks after deploying the fix, as field data is sampled from real users.
// SCAN_YOUR_CODE
Does your theme have this bug?
Paste your code. Syphio automatically detects and fixes this error and hundreds of others — in seconds.
Validate my Liquid →