Skip to content
What To Fix First

How to fix a slow LCP on a Shopify store

A slow LCP on Shopify is nearly always the hero: an image requested at full size because the theme gives image_url no width, lazy-loaded even though it is above the fold, or replaced by an autoplaying video. Behind that sit app scripts loading before the paint and, occasionally, a Liquid loop that slows the first byte. Fix the hero first.

By , who built this checker and writes the guides. Published How the tool ranks fixes

Where the time goes on Shopify

The LCP guide splits LCP into four phases — server, discovery, download, render — and the Shopify speed test shows which phase yours is in. On Shopify the server phase is usually short, so the time sits in the other three, and almost always in the hero image: discovered late because the theme lazy-loads it, downloaded slowly because the theme asked for the original, or rendered late because app scripts run first. Fix the hero first; it is most of the problem on most stores.

1. Request the hero at the right size

Shopify’s CDN resizes, compresses and converts images on the fly, but only when the theme asks. A tag with no width gets the original upload, which for a hero shot off a camera is a 3–5 MB file. The fix is in the section’s Liquid:

{%- comment -%} Before: original upload, whatever size the merchant uploaded {%- endcomment -%}
<img src="{{ section.settings.image | img_url: 'master' }}">

{%- comment -%} After: sized, responsive, eager, high priority {%- endcomment -%}
{{ section.settings.image
   | image_url: width: 1500
   | image_tag:
       widths: '375, 550, 750, 1100, 1500, 1780, 2000',
       sizes: '100vw',
       loading: 'eager',
       fetchpriority: 'high',
       class: 'banner__media' }}

widths produces a srcset so phones get phone-sized files; sizes: '100vw' tells the browser the image spans the viewport. Dawn’s image banner section already does this; check that customisations or a purchased theme did not replace it with a bare tag.

2. Never lazy-load the hero

Many themes add loading="lazy" to every image, the hero included. On the LCP element that is the worst possible setting: the browser deprioritises the one file the visitor is waiting for. In Dawn’s image banner and slideshow, the first image is eager by default; if the section has been edited, or on another theme, make sure the first image above the fold has loading: 'eager' and fetchpriority: 'high' as in the snippet above, and every image below it lazy.

For product pages the same applies to the featured image in the media gallery: the first one eager, the thumbnails and remaining slides lazy. Dawn’s product-media-gallery section handles this; confirm with the page source that the first <img> in the gallery has no loading="lazy".

3. Preload it

When the hero is set in CSS as a background image, or lives inside a slider the browser discovers late, a preload in the head starts the download before the section is parsed:

{%- comment -%} theme.liquid <head> — only for the one image that is the LCP {%- endcomment -%}
{%- if template == 'index' -%}
  {{ settings.hero_image | image_url: width: 1500 | preload_tag: as: 'image', fetchpriority: 'high' }}
{%- endif -%}

One image only. Preloading several competes with the one that matters and slows it. Better than a background image is a real <img> the browser finds in the HTML, which needs no preload at all.

4. Replace the video background

A home page video background is both the LCP element and the reason everything else is late. Section settings → turn the video off and use the poster image, sized as above. If the brand insists on motion, keep the poster as the LCP and start the video after load with a small script, so it never competes with the first paint.

5. Get app scripts out of the way

{{ content_for_header }} in theme.liquid injects every installed app’s script tags, and you cannot edit what it outputs. What you can do:

  • Uninstall apps you do not use. Reviews, upsell, currency, wishlist and countdown apps each add a script to every page. Ten apps is often a second of render delay on a phone.
  • Remove leftover snippets. Uninstalling does not always clean the theme. Search theme.liquid, layout/ and snippets/ for the names of apps you removed, and for <script src= tags pointing at third-party domains.
  • Prefer theme app extensions (app blocks and embeds) over apps that inject into theme.liquid; they load through Shopify’s own loader, which defers them.
  • Consolidate pixels. Meta, TikTok, Pinterest, Klaviyo, Google Ads: use Shopify’s Customer Events (pixels) framework so they load in the sandbox after the page, rather than as head scripts.

The render-blocking guide explains why a script in the head delays the paint at all; the unused JavaScript guide covers the rest of the app weight.

6. Fonts

A hero headline as the LCP element is delayed by the font it waits for. Use Shopify’s font library (served from Shopify’s CDN with font-display: swap) and preload the heading font:

{{ settings.type_header_font | font_url | preload_tag: as: 'font', type: 'font/woff2', crossorigin: 'anonymous' }}

A theme that embeds a Google Fonts stylesheet instead adds two render-blocking connections; replace it.

7. If the server phase is the slow one: Liquid

The one case where a Shopify store genuinely has a slow first byte. Rendering a collection with a nested loop over every product’s variants, building a mega-menu by iterating all collections and their products, or a snippet that calls all_products inside a loop makes Shopify’s renderer do real work on every request, and the page cache does not save you because the page is personalised by cart state. The checker reports the first byte in the metrics table; over 600 ms on Shopify means open the theme and look for loops inside loops. Paginate collections, move menu data to a metaobject, and never call all_products in a loop.

The order that works

  1. Hero image: sized with image_url: width, eager, high priority, real <img>.
  2. Video background off; poster image instead.
  3. Uninstall unused apps; grep the theme for leftovers.
  4. Move pixels to Customer Events.
  5. Preload the heading font.
  6. Only if the first byte is slow: audit Liquid loops.

Everything above is free: the CDN does the resizing once the theme asks with a width, and Shopify's own font library and pixel framework replace the third-party versions. If the media library itself is thousands of original uploads at camera resolution and you want them cleaned up in bulk rather than relying on the CDN per request, a batch image service is the practical route. For that we use ShortPixel. That is an affiliate link: we earn a commission if you sign up, at no extra cost to you.

Check it worked

Re-run the Shopify speed test. The LCP timeline should show the download phase shrinking after step 1 and the render phase after steps 3–4; LCP under 2.5 s in the lab is the target. Then run it on a product page and a collection page — each has its own hero. If layout shift is now the headline, the Shopify CLS guide is next.

Common questions

Can I speed up Shopify's servers or CDN?
No, and they are rarely the problem. Shopify's first byte is usually well under 600 ms. When the checker does report a slow server on a Shopify store, the cause is nearly always Liquid — a loop over every product in a collection, or a menu built by iterating all collections — not infrastructure.
Which is the LCP element on a Shopify page?
On the home page, the image banner or first slide; on a product page, the featured product image; on a collection page, the first product card image or the collection banner. The checker's timeline names the element Lighthouse chose and shows which phase — server, discovery, download, render — the time sits in.
Do I need an image optimisation app?
Usually not. Shopify's CDN already resizes, compresses and serves WebP or AVIF when the theme requests an image with a width. An app is worth considering only for cleaning up a library of original uploads, and even then the theme's image_url width is the change that matters.
Does removing apps really help LCP?
Yes, when their scripts run before the paint. Every app that injects a script tag delays render by the time the browser spends fetching and executing it; ten apps can be a second on a phone. Removing unused apps, and checking theme.liquid for snippets left behind, is the second-largest LCP win after the hero image.
What about the video background on my home page?
It is the LCP element or delays it, and it is several megabytes before anything feels finished. Replace it with a poster image that loads eagerly, and if the video must stay, load it after the page is interactive.

Check a page against this

Runs the same Core Web Vitals test as the Shopify speed test.

Free, no signup, no ads. We keep nothing except the shareable result, for 30 days.

Enter any public URL. You’ll get the one change that recovers the most load time, what it’s worth, and the measurements underneath.

Related guides

All guides