Shopify Speed Optimization: Fixing LCP on Collection Pages Without Killing Apps
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.

- 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:
- 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.
- Search Console's Core Web Vitals report, which groups similar URLs. On a big store, collection pages usually form their own group.
- 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:
{% 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
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 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:
{%- 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:
<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.
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
collectionsorall_productsin 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
sizesattribute 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.
The fix order, in one list#
- Confirm the LCP element on mobile and desktop.
- Eager-load the first row; one image gets
fetchpriority="high". - Correct
sizes, and no CSS background images for LCP content. - Turn off reveal animations above the fold.
- Make sure the grid renders in HTML.
- Restrict or delay apps by template; remove leftover code.
- Profile Liquid if TTFB is slow.
It's part of the Shopify SEO checklist, our Shopify speed optimization service and our wider Shopify technical SEO work. For the wider technical picture, see the Shopify technical SEO guide.
Questions people ask about this
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.
Want this done on your store?
Shopify speed work measured on real-user Core Web Vitals: app bloat, collection-page LCP, images, theme code and third-party scripts, with an honest view of what speed does for rankings.
More from Technical SEO

The Shopify Apps Slowing Down Your Store and Quietly Hurting SEO (Plus a 20-Minute Audit)
Shopify apps slow down your store, leave code behind after you uninstall them, and sometimes change what Google sees. This 20-minute audit shows where to look and what to remove.

Crawled – Currently Not Indexed on Shopify: Why Google Skips Your Pages
Crawled – currently not indexed means Google fetched a page and chose to leave it out. On Shopify most of those URLs are harmless; here is how to find the few that cost you sales and fix them.

Is Shopify Good for SEO? An Honest Answer From a Shopify-Only Agency
Shopify is good for SEO for most ecommerce brands, and its real limits are manageable. Here's what the platform does well, where it falls short, how it compares with WooCommerce, BigCommerce and Magento, and when the limits matter.