# Shopify Speed Optimization: Fixing LCP on Collection Pages Without Killing Apps

Source: https://www.smartecomseo.com/blog/shopify-speed-optimization/  
Published: 2026-09-24  
Updated: 2026-09-29

Why Shopify collection pages fail LCP, how to find the real LCP element, and the fixes in order: image loading, animations, app scripts and Liquid render time.

## Key takeaways

- Find the real LCP element on your collection template before changing anything. On mobile it's usually the first product image or the collection banner.
- Never lazy-load the first row of products, and give exactly one image fetchpriority="high". Dawn eager-loads only the first two product cards.
- Reveal-on-scroll animations can delay LCP even after the image has downloaded, according to Shopify's own performance guidance.
- Most apps don't need removing. Load them only on the templates that use them, and defer chat, popups and widgets until after the page renders.
- Be wary of speed apps and services that raise scores without changing what shoppers see. Shopify documents how they cheat Lighthouse.

Shopify speed optimization usually starts in the wrong place: a PageSpeed score for the home page and a list of apps to uninstall. On big catalogs, the template that fails Core Web Vitals most often is the collection page, and the cause is rarely the app you'd guess. It's usually the first row of product images loading late.

This guide covers how to find the real problem on collection pages and fix it in order, without removing the apps that make you money. We used Shopify's theme performance documentation, the Dawn theme source code and Google's Core Web Vitals thresholds, checked in September 2026.

## What "good" means, and where to measure it

Google assesses Core Web Vitals at the 75th percentile of real visits:

| Metric | Good | Needs improvement | Poor |
| --- | --- | --- | --- |
| Largest Contentful Paint (LCP) | ≤ 2.5 s | 2.5–4 s | > 4 s |
| Interaction to Next Paint (INP) | ≤ 200 ms | 200–500 ms | > 500 ms |
| Cumulative Layout Shift (CLS) | ≤ 0.1 | 0.1–0.25 | > 0.25 |

Use field data first. Three sources, in the order we check them:

1. **Shopify's web performance dashboard.** From the admin, go to **Online Store** and open the LCP, INP or CLS summary. It uses real user data, can be broken down by page type, and marks app installs and theme changes on the timeline. Data can lag by up to 36 hours.
2. **Search Console's Core Web Vitals report**, which groups similar URLs. On a big store, collection pages usually form their own group.
3. **PageSpeed Insights** for one URL, to see field data next to a lab run.

Lab scores are for debugging. A Lighthouse score of 45 on a collection page that passes LCP in the field is not an emergency; a failing field LCP is, even if the lab score looks fine.

## Step 1: Find the real LCP element

Open a busy collection in Chrome, open DevTools, switch to the **Performance** panel, turn on mobile CPU and network throttling and record a reload. The LCP marker names the element. On Shopify collection pages it's almost always one of these:

| LCP element | Typical cause when it's slow |
| --- | --- |
| First product card image | Lazy-loaded, low priority, or rendered by JavaScript |
| Collection banner image | CSS background image, oversized file, or hidden behind an animation |
| Collection title or description text | Late web fonts or render-blocking CSS and scripts |
| A popup or promo bar | An app's dialog is larger than your content and has become the LCP element |

Check both mobile and desktop. On a two-column mobile grid the first product image is often the LCP element; on desktop the banner often is.

## Step 2: Fix image loading on the first row

This is the highest-value fix on most collection pages. Shopify's performance guidance puts it plainly: never lazy-load the LCP image, and mark it with `fetchpriority="high"`. By default, browsers discover images at low priority and only raise them once layout shows they're in the viewport. The attribute removes that delay.

In the Dawn source we read, the collection grid passes `lazy_load: false` to the first two product cards and lazy-loads the rest:

```liquid
{% assign lazy_load = false %}
{%- if forloop.index > 2 -%}
  {%- assign lazy_load = true -%}
{%- endif -%}
```

That's fine on a two-column mobile grid. On a four-column desktop grid, cards three and four in the first row are lazy-loaded, and no card gets `fetchpriority`. A change we often make in the grid section:

```liquid
{%- liquid
  assign lazy_load = true
  if forloop.index <= 4
    assign lazy_load = false
  endif
  assign fetch_priority = 'auto'
  # Only when no banner image sits above the grid;
  # otherwise the banner gets the high priority.
  if forloop.first and collection.image == blank
    assign fetch_priority = 'high'
  endif
-%}
{% render 'card-product',
  card_product: product,
  lazy_load: lazy_load,
  fetch_priority: fetch_priority
%}
```

Then, in the card snippet, add `fetchpriority="{{ fetch_priority | default: 'auto' }}"` to the product image. Setting names differ by theme; the idea is the same. The first visible row loads eagerly, and exactly one image, whichever you confirmed as the LCP element, gets high priority. Shopify's docs warn that overusing `fetchpriority="high"` can make things worse.

For section-level images such as banners, Shopify recommends branching on `section.index`. Dawn's image banner already gives the first section `fetchpriority: 'high'`. Note that `section.index` is `nil` in the theme editor and in Section Rendering API responses, so write the lazy branch as `section.index > N` and let `nil` fall through to eager.

### Get the image size right too

Dawn's product cards include a `sizes` attribute that matches the grid layout. Custom themes and app-built grids often don't, and a phone ends up downloading a 1,500-pixel image for a 180-pixel card. Use `image_url` with `image_tag` (or a correct `srcset` and `sizes`), and never use a CSS `background-image` for a banner that might be the LCP element; the browser can't discover it early.

## Step 3: Turn off animations that hide the LCP image

Many themes fade product cards or sections in as they scroll into view. Shopify's performance docs list "Don't hide the LCP image behind animations" as a high-impact fix: fade-in and reveal animations delay the LCP event even after the image has downloaded.

In Dawn-based themes, the setting is **Theme settings > Animations > Reveal sections on scroll**, and it's on by default in Dawn. Turn it off, or exclude the first section and first row of cards from it, and compare field LCP after a couple of weeks.

## Step 4: Keep the grid in HTML

If a search, filter or merchandising app replaces your collection grid with a JavaScript-rendered one, LCP now waits for the app's script, its API call and its render. Shopify's guidance is to render essential content in Liquid and HTML, not JavaScript.

Test it: load the collection with JavaScript disabled. If the product grid is empty, the grid depends on the app. Options, in order of preference:

- Use the app's server-rendered or Liquid-based mode, if it has one.
- Use Shopify's native Search & Discovery filtering, which renders through the theme.
- Keep the app but make sure the first row renders server-side and the app enhances it afterwards.

This also matters for SEO beyond speed: product links that only exist after JavaScript runs are harder for crawlers to find. See [Shopify faceted navigation SEO](/blog/shopify-faceted-navigation-seo/) for the filter side.

## Step 5: Manage apps without removing them

Shopify's own guidance on render-blocking apps asks four questions for each app: is it used, does it need to load on every page, is there a lighter alternative, and can it load after the first paint? On collection pages, the answers usually look like this:

| App type | Needed on collection pages? | Strategy |
| --- | --- | --- |
| Reviews | Star ratings on cards, yes; full widget, no | Show stars from the `reviews.rating` metafield in Liquid; load the widget only on product pages |
| Chat | Rarely at first paint | Load after the first interaction or a delay |
| Email and SMS popups | Not before content | Delay; make sure the dialog can't become the LCP element |
| Upsell and bundles | Usually product and cart only | Restrict to those templates |
| A/B testing | Only while a test runs | Remove anti-flicker snippets when no test is live |
| Analytics and pixels | Yes, but not blocking | Load async or through Shopify's customer events |

Many apps load through **app embeds**, which you can switch off per theme under **Customize > App embeds**. For scripts added directly to the theme, restrict them to the templates that need them:

```liquid
{%- if template.name == 'product' -%}
  <script src="{{ 'reviews-widget.js' | asset_url }}" defer></script>
{%- endif -%}
```

And for a chat widget, load it only once the shopper does something:

```html
<script>
  (function () {
    var loaded = false;
    function loadChat() {
      if (loaded) return;
      loaded = true;
      var s = document.createElement('script');
      s.src = 'https://chat.example.com/widget.js';
      s.async = true;
      document.head.appendChild(s);
    }
    ['pointerdown', 'keydown', 'scroll'].forEach(function (evt) {
      window.addEventListener(evt, loadChat, { once: true, passive: true });
    });
    setTimeout(loadChat, 8000);
  })();
</script>
```

Replace the URL with your provider's script, and check that its settings allow delayed loading. Also search `theme.liquid` and your snippets for scripts from apps you've uninstalled. Apps that edited theme code directly, instead of using theme app extensions, often leave code behind.

> **Beware of speed apps that only move the score:** Shopify's documentation describes "speed optimization" apps and freelance services that detect Lighthouse and serve it a different page, or inject an invisible element to hijack the LCP measurement. Real shoppers get no benefit. Shopify's checks: compare PageSpeed Insights with Lighthouse in an incognito window (a gap of 20+ points is a red flag), inspect what the LCP element actually is, and compare with the web performance dashboard.

### Keep app content from shifting the layout

Apps that inject star ratings, badges or "buy now, pay later" messages after load push the grid around and hurt CLS. Shopify's guidance is to use app blocks and reserve space for them with a `min-height` in CSS, so the card is the right size before the app content arrives. Star ratings rendered in Liquid from the `reviews.rating` metafield avoid the problem entirely, because they arrive with the HTML.

## Step 6: Reduce Liquid render time

If Time to First Byte is slow on collections but fine elsewhere, the problem is server-side Liquid, and client-side fixes won't help. Common causes on big catalogs:

- **Too many products per page.** Dawn's setting ranges from 8 to 36, with 16 as the default. Every card renders its own Liquid.
- **Swatches and quick-add** that loop over every variant of every product on the page. With products carrying dozens or hundreds of variants, this adds up quickly.
- **Mega menus** with hundreds of links rendered on every page.
- **Nested loops** over `collections` or `all_products` in snippets.

Shopify's Theme Inspector for Chrome profiles Liquid render time per file, which shows which snippet is slow. Shopify's docs also recommend deferring dialog and drawer content until it opens, so a quick-view modal doesn't render on page load for every card.

## High-ticket and Chinese brand specifics

Two patterns we see often:

- **High-ticket collections** use large lifestyle banners above the grid. Beautiful, and frequently the LCP element. Give the banner an `<img>` with correct sizes and high priority, and keep its text as real HTML text, not baked into the image.
- **Chinese brands coming from Amazon** upload marketplace-style images with text overlays and heavy PNG files. Shopify's CDN resizes images to the requested width, so the real issue is usually the `sizes` attribute and the number of images per card, not the upload size.

## Measuring the result

Field data moves slowly. Google's Chrome UX Report uses a rolling 28-day window, and Shopify's dashboard reports on the last 30 days. Deploy fixes to one template at a time, note the date, and compare the collection page-type line in Shopify's dashboard and the collection URL group in Search Console after three to four weeks.

Speed is a ranking factor through page experience, but it's rarely the reason a collection ranks on page three. Relevance, copy and links usually are. Fix LCP because it affects conversions and removes a disadvantage, then spend the bigger effort on the pages themselves, as covered in [the collection page SEO guide](/blog/shopify-collection-page-seo/).

**Collection pages failing LCP?** We find the real LCP element on each template, fix image loading and app scripts, and keep the apps that sell. [See our speed service](/shopify-seo-services/speed-optimization/)

## The fix order, in one list

1. Confirm the LCP element on mobile and desktop.
2. Eager-load the first row; one image gets `fetchpriority="high"`.
3. Correct `sizes`, and no CSS background images for LCP content.
4. Turn off reveal animations above the fold.
5. Make sure the grid renders in HTML.
6. Restrict or delay apps by template; remove leftover code.
7. Profile Liquid if TTFB is slow.

It's part of the [Shopify SEO checklist](/blog/shopify-seo-checklist/), our [Shopify speed optimization](/shopify-seo-services/speed-optimization/) service and our wider [Shopify technical SEO](/shopify-seo-services/technical-seo/) work. For the wider technical picture, see [the Shopify technical SEO guide](/blog/shopify-technical-seo-guide/).

## FAQs

### Why is LCP slow on my Shopify collection pages?

Usually because the LCP element, often the first product image or the collection banner, is lazy-loaded, fetched at low priority, hidden behind a fade-in animation, or rendered by a JavaScript app instead of Liquid. Slow Liquid from swatches and large product counts, and render-blocking app scripts, are the next most common causes. Confirm the LCP element in Chrome DevTools first.

### Do I need to uninstall apps to speed up Shopify?

Rarely. Remove apps you don't use and code left behind by uninstalled apps, but most business-critical apps can stay. Load them only on the templates that need them, switch off app embeds where they aren't used, and delay chat widgets and popups until after the page renders. Shopify's own guidance recommends this evaluate-then-defer approach.

### What is a good Core Web Vitals score for Shopify?

Google's thresholds apply to every site: LCP of 2.5 seconds or less, INP of 200 milliseconds or less and CLS of 0.1 or less, measured at the 75th percentile of real visits. Shopify's web performance dashboard in the admin shows these from real user data and can be broken down by page type, which is the easiest way to watch collection pages.

### Are Shopify speed optimization apps worth it?

Be careful. Shopify's documentation describes apps and services that detect testing tools and serve them a different page, or inject elements to fake a better LCP, while real shoppers see no improvement. Legitimate fixes change when the main content appears for real visitors. Compare PageSpeed Insights with Lighthouse and with Shopify's field data before trusting a score jump.

### How long until Shopify speed fixes show in Search Console?

Usually three to four weeks or more. Search Console's Core Web Vitals report is based on Chrome UX Report field data, which uses a rolling 28-day window, and Shopify's dashboard reports on the last 30 days. Deploy one fix at a time, note the date, and compare the collection page group after the window has turned over.