Shopify Speed Optimization: The Complete Guide

Shopify speed optimization is not about chasing a perfect Lighthouse score once and forgetting about it.
For most Shopify stores, speed problems come from a few repeat offenders: heavy themes, too many apps, oversized images, third-party scripts, render-blocking CSS, web fonts, and dynamic widgets that shift the page after it loads.
These issues directly affect conversions, SEO, Core Web Vitals, and the user experience. A product page that takes too long to show the main image will hurt LCP. A review widget that appears late can hurt CLS. A stack of tracking scripts, chat widgets, upsells, and popups can make the page feel slow even after it visually loads.
The good news is that Shopify gives you enough control to fix most front-end performance issues. You cannot change Shopify's hosting stack like you would on a custom server, but you can improve the theme, Liquid output, images, fonts, app usage, and third-party scripts.
In this guide, we will go through a practical Shopify speed optimization workflow that you can apply to real stores.
How to Test Shopify Store Speed Properly
Before optimizing anything, you need a reliable baseline.
Do not rely on one Lighthouse score from your desktop browser. It is useful for debugging, but it is not enough to judge Shopify page speed. Your visitors use different devices, networks, locations, and page types.
I recommend starting with the SpeedVitals Web Vitals Test and testing the pages that actually matter to your store.
For most Shopify stores, that means testing:
- Home page
- Product pages
- Collection pages
- Cart page
- High-traffic landing pages
- Blog posts if they drive organic traffic
- Pages with heavy apps, reviews, recommendations, or upsells
Do not assume that optimizing the home page fixes the whole store. A Shopify product page can have a completely different performance profile because it may include image galleries, variant selectors, reviews, recommendation widgets, sticky add-to-cart bars, and app scripts.
Test Mobile First
Mobile performance is usually more important for Shopify Core Web Vitals.
Mobile devices have less CPU power, slower networks, smaller screens, and more layout pressure. JavaScript execution, image size, and layout shifts are usually more visible on mobile than desktop.
When testing, record:
| Metric | What It Tells You | Common Shopify Cause |
|---|---|---|
| LCP | How quickly the main visible content appears | Hero image, product image, render-blocking CSS, slow theme rendering |
| CLS | Whether visible content moves unexpectedly | Images without dimensions, reviews, apps, banners, fonts |
| INP or TBT | How heavy JavaScript feels to users | Apps, analytics, popups, product widgets, chat scripts |
| TTFB | How quickly the document starts loading | Liquid complexity, redirects, app proxy requests, geographic latency |
| Page Weight | How much data the page downloads | Large images, fonts, JavaScript, app assets |
| Request Count | How many resources the browser fetches | Apps, trackers, icon libraries, CSS/JS files |
You should also test from your important geographies. If most of your customers are in the United States, India, Europe, or Australia, test those locations separately instead of using only the nearest test server.
For real users, use SpeedVitals RUM to monitor Shopify Core Web Vitals over time. Lab tests help you diagnose issues, while RUM shows what real visitors are experiencing.
Understand the Shopify Performance Bottlenecks
Shopify is a managed platform, so the optimization approach is different from WordPress or a custom backend.
You do not install server caching plugins, tune Nginx, or move the store to another host. Instead, most Shopify speed optimization work happens in the theme, apps, assets, Liquid templates, and third-party scripts.
Here are the most common bottlenecks.
| Bottleneck | Why It Hurts Performance | What To Do |
|---|---|---|
| Theme bloat | Loads too much CSS, JavaScript, sections, animations, and layout code | Use a lightweight theme and remove unused sections |
| Too many apps | Apps inject scripts, CSS, fonts, app blocks, and app proxy calls | Remove unused apps and audit leftover code |
| Render-blocking CSS/JS | Browser waits before rendering above-the-fold content | Reduce, defer, or conditionally load assets |
| Large images | Slows LCP and increases page weight | Resize, compress, and use responsive images |
| Third-party scripts | Compete for main-thread time and network bandwidth | Remove, delay, or conditionally load |
| Fonts and icons | Add extra requests and can cause layout shifts | Reduce font families/weights and avoid icon fonts |
| Poor Liquid structure | Creates slow or bloated HTML output | Simplify loops, snippets, and section logic |
| App proxy requests | Depend on external app servers during page interactions | Avoid critical UX depending on slow app responses |
This is why Shopify performance is often less about one magic setting and more about removing unnecessary work.
Choose a Fast Shopify Theme
Your theme is the foundation of Shopify theme performance.
A fast theme gives you cleaner Liquid output, less JavaScript, fewer global assets, better section architecture, and fewer layout issues. A bloated theme does the opposite. It may look flexible in the editor, but it can ship sliders, animations, unused sections, icon libraries, and JavaScript for features you are not even using.
I recommend starting with a lightweight Online Store 2.0 theme whenever possible. Shopify's newer theme architecture makes it easier to manage sections and templates, but the theme still needs to be built carefully.
A good Shopify theme should:
- Load only the CSS and JavaScript required for the current page.
- Avoid heavy sliders and animation libraries by default.
- Use responsive images correctly.
- Include image dimensions to prevent Shopify CLS issues.
- Avoid loading all section assets globally.
- Keep product page JavaScript small and predictable.
- Work well without excessive app-based page building.
A fast theme does not compensate for excessive apps and third-party scripts. I have seen stores switch to a better theme and still fail Core Web Vitals because the same old app stack kept loading on every page.
Theme replacement should usually come after an app and script audit, not before it.
Remove Unnecessary Shopify Apps
Shopify apps are one of the biggest reasons stores become slow over time.
An app may add:
- JavaScript files
- CSS files
- Web fonts
- Tracking scripts
- App blocks
- Snippets
- Liquid includes
- App proxy requests
- Third-party network connections
The difficult part is that app assets are often loaded globally even when the app feature is visible on only one template.
For example, a reviews app may load on the home page, collection pages, product pages, and cart page, even if reviews are only shown on product pages. A popup app may load on every page even if it appears only once per visitor.
App Audit Checklist
Go through every installed app and ask:
- Does this app directly affect revenue or operations?
- Does it load front-end JavaScript?
- Does it load on every page?
- Is the feature still being used?
- Can this be implemented inside the theme instead?
- Does the app duplicate another app's functionality?
- Does it add fonts, icons, or tracking pixels?
- Does uninstalling it leave code in theme files?
Some app code remains even after uninstalling the app. Check theme files such as:
theme.liquid- Product templates
- Collection templates
- Cart templates
snippets/sections/- App embed settings
- Custom Liquid blocks
Do not remove unfamiliar code blindly on production. Duplicate the theme, make changes in the copy, and test the user flow before publishing.
Optimize Shopify Images
Images are usually the largest part of a Shopify page.
If you want to optimize Shopify images, focus on four things:
- Correct dimensions
- Responsive delivery
- Modern formats
- Correct loading priority
Avoid Uploading Oversized Images
Do not upload a 5000px wide hero image if it is never displayed above 1600px.
Shopify's image CDN can resize images using Liquid filters, but uploading reasonably sized source images is still a good habit. Large original files make theme development harder and can lead to accidental oversized output.
For product images, keep high-quality originals, but make sure your theme outputs the right size for the actual layout.
Use Shopify Image CDN Transformations
Shopify's image_url and image_tag filters help generate optimized image output. You can learn more in Shopify's official documentation for the image_url filter and image_tag filter.
A simple product image example:
{{ product.featured_image
| image_url: width: 900
| image_tag:
loading: 'lazy',
widths: '360, 540, 720, 900',
sizes: '(max-width: 768px) 100vw, 50vw',
alt: product.featured_image.alt
}}
This gives the browser multiple image candidates instead of forcing every device to download the same large file.
Add Width and Height
Images should reserve space before loading. This is important for Shopify CLS.
If your theme outputs raw image tags, make sure the dimensions are present:
<img
src="{{ product.featured_image | image_url: width: 900 }}"
width="{{ product.featured_image.width }}"
height="{{ product.featured_image.height }}"
alt="{{ product.featured_image.alt | escape }}"
loading="lazy"
>
The exact rendered size can still be controlled with CSS, but the browser needs the intrinsic ratio early.
For a deeper comparison of modern image formats, check our guide on WebP vs AVIF.
Do Not Lazy Load the LCP Image
Lazy loading is useful for below-the-fold images. It is usually bad for the LCP image.
On Shopify, the LCP element is often:
- Hero banner image
- Main product image
- Collection header image
- Large heading text
- Promotional banner
If your hero or main product image is above the fold, do not use loading="lazy" on it.
Use eager loading and higher priority instead:
{{ product.featured_image
| image_url: width: 1200
| image_tag:
loading: 'eager',
fetchpriority: 'high',
widths: '600, 900, 1200',
sizes: '(max-width: 768px) 100vw, 60vw',
alt: product.featured_image.alt
}}
This should be used carefully. Do not set fetchpriority="high" on every image. Use it only for the actual above-the-fold LCP candidate.
Fix the Shopify LCP Element
Shopify LCP optimization starts by identifying the LCP element.
Do not guess. Run a test, look at the LCP element, and check the waterfall. If the LCP element is a product image, the fix is different from a text heading delayed by CSS or a hero banner blocked by JavaScript.
Common Shopify LCP problems include:
| LCP Problem | Shopify Example | Fix |
|---|---|---|
| LCP image lazy loaded | Product image or hero banner has loading="lazy" | Load it eagerly |
| LCP image discovered late | Image is injected by JavaScript or CSS background | Output it in HTML early |
| Oversized image | Mobile downloads desktop hero image | Use responsive image widths |
| Render-blocking CSS | Large theme CSS blocks first paint | Reduce CSS and inline only critical parts carefully |
| JavaScript blocks rendering | Sliders, animations, or app scripts run early | Defer or delay non-critical scripts |
| Slow TTFB | HTML response starts late | Reduce Liquid complexity, redirects, and app proxy dependencies |
If the LCP image is discovered too late, preloading can help. We have a separate guide on how to preload the LCP image correctly.
For Shopify, a preload can be added in theme.liquid or a relevant section, but you should only preload the image that is very likely to be the LCP element for that template and viewport.
Example:
{% if template.name == 'product' and product.featured_image %}
<link
rel="preload"
as="image"
href="{{ product.featured_image | image_url: width: 1200 }}"
imagesrcset="
{{ product.featured_image | image_url: width: 600 }} 600w,
{{ product.featured_image | image_url: width: 900 }} 900w,
{{ product.featured_image | image_url: width: 1200 }} 1200w
"
imagesizes="(max-width: 768px) 100vw, 60vw"
>
{% endif %}
Do not preload multiple large images. It can make Shopify page speed worse by competing with CSS, fonts, and the actual LCP resource.
Reduce JavaScript Execution
JavaScript is one of the biggest Shopify performance problems.
A store may start with a clean theme, then slowly add:
- Analytics
- Google Tag Manager
- Meta Pixel
- TikTok Pixel
- Klaviyo
- Review apps
- Chat widgets
- Popup apps
- Upsell apps
- Recommendation widgets
- A/B testing tools
- Heatmaps and session recording
- Affiliate tracking
Each script may look small alone, but together they compete for network bandwidth and main-thread execution time.
This can hurt INP, TBT, and sometimes LCP.
Delay Low-Priority JavaScript
Scripts that are not needed for the first render can often be delayed until user interaction or after the main content has loaded.
Good candidates include:
- Chat widgets
- Heatmaps
- Social widgets
- Popup scripts
- Non-critical analytics
- Recommendation widgets
- Review widgets below the fold
- Some marketing pixels
This is the same idea explained in our guide on delaying JavaScript, but you need to be more careful on Shopify because scripts may control product options, cart behavior, checkout-related flows, or app blocks.
Do Not Delay Critical Store Functionality
Do not blindly delay:
- Variant selectors
- Add-to-cart logic
- Cart drawer scripts
- Payment button scripts
- Consent scripts required before tracking
- Inventory or pricing scripts required above the fold
- Product personalization scripts used immediately
The goal is not to delay everything. The goal is to delay scripts that do not need to run before the user can see and use the page.
Load Scripts Conditionally
If a script is needed only on product pages, do not load it on collection pages.
Example:
{% if template.name == 'product' %}
<script src="{{ 'product-gallery.js' | asset_url }}" defer></script>
{% endif %}
For app scripts, check whether the app supports conditional loading or app embeds that can be enabled only where needed.
Optimize CSS and Remove Unused Code
Shopify themes often ship more CSS than a page needs.
This happens because one global stylesheet may include:
- Header styles
- Footer styles
- Product page styles
- Collection grid styles
- Slideshow styles
- Drawer styles
- Modal styles
- Form styles
- App styles
- Unused sections
The browser has to download and parse that CSS before rendering the page, especially if it is render-blocking.
Load CSS by Template or Section
Where possible, load CSS only on templates that need it.
{% if template.name == 'product' %}
{{ 'product.css' | asset_url | stylesheet_tag }}
{% endif %}
For section-specific CSS, keep the CSS close to the section when it is not needed globally.
This does not mean you should split every small rule into separate files. Too many small files can also create overhead. The goal is to avoid loading large unused CSS bundles on every page.
Be Careful With Critical CSS
Critical CSS can improve first render, but it can also break layouts if done aggressively.
Avoid:
- Removing CSS that is needed shortly after initial render
- Inlining a huge amount of CSS into the HTML
- Creating different critical CSS that does not match the final layout
- Breaking app widgets or dynamic sections
CSS optimization should improve rendering without changing the layout users see.
Optimize Fonts and Icons
Fonts can hurt Shopify page speed in two ways:
- They add extra requests.
- They can cause text reflow when the web font replaces the fallback font.
Keep font usage simple.
I recommend:
- Use one or two font families at most.
- Use fewer weights.
- Avoid loading italic styles unless used.
- Prefer system fonts when acceptable.
- Self-host fonts when possible.
- Preload only the most critical above-the-fold font file.
- Use
font-display: swaporfont-display: optionaldepending on the design.
Example:
@font-face {
font-family: "Brand Sans";
src: url("{{ 'brand-sans.woff2' | asset_url }}") format("woff2");
font-display: swap;
font-weight: 400;
}
Icon fonts are another common problem.
Loading a full icon font library for five icons is wasteful. Use inline SVG icons or a custom SVG sprite instead of large icon font libraries when possible.
This is especially important for Shopify themes that load multiple icon sets from the theme and apps at the same time.
Reduce Layout Shifts
Shopify CLS issues usually come from elements that load late without reserved space.
Common causes include:
- Product images without dimensions
- Hero banners without fixed ratios
- Review widgets that appear after load
- Product recommendation blocks
- Announcement bars
- Sticky add-to-cart bars
- Cookie banners
- App embeds
- Font swaps
- Sliders
- Dynamically injected discounts or upsells
The fix is to reserve space before the element appears.
For images and media:
.product-card__image {
aspect-ratio: 1 / 1;
overflow: hidden;
}
.product-card__image img {
width: 100%;
height: 100%;
object-fit: cover;
}
For review widgets:
.product-reviews {
min-height: 360px;
}
For recommendation sections:
.product-recommendations {
min-height: 420px;
}
Do not inject dynamic content above existing content after the page has started loading. If you must show an announcement bar, render it early or reserve the space from the beginning.
For a deeper layout stability workflow, check our guide on how to reserve space to prevent layout shift.
Use Shopify CDN Effectively
Shopify handles a lot of CDN complexity for you.
Theme assets, product images, and many static resources are served through Shopify's infrastructure. This is one of the advantages of using a managed platform.
However, you still control how assets are referenced.
You should:
- Use Shopify image transformations instead of hardcoding huge original images.
- Avoid serving critical images from unnecessary third-party CDNs.
- Keep theme assets compressed and small.
- Avoid loading large videos directly above the fold.
- Remove unused files from the theme when they are no longer referenced.
- Use the
asset_urlfilter for theme assets.
Example:
<script src="{{ 'theme.js' | asset_url }}" defer></script>
Avoid adding extra CDN layers for critical Shopify assets unless you have a specific reason. Extra DNS lookups and connection setup can slow down the first view.
For a broader CDN perspective, our guide on the best CDN provider explains what CDNs can and cannot solve for web performance.
Improve Shopify TTFB and Server Response Time
Shopify hosting is managed, so you cannot fix Shopify TTFB by changing PHP versions, installing server cache plugins, or tuning the origin server.
That advice applies to self-hosted platforms, not Shopify.
However, Shopify TTFB can still be affected by:
- Heavy Liquid templates
- Large nested loops
- Complex section rendering
- Excessive snippet includes
- Too many redirects
- App proxy requests
- External personalization logic
- Geographic latency
- Pages waiting on app-generated content
The first HTML document should be as simple and fast as possible.
Reduce Liquid Complexity
Avoid unnecessary loops inside heavily used templates.
Bad pattern:
{% for product in collections.all.products %}
{% render 'product-card', product: product %}
{% endfor %}
Better pattern:
{% paginate collection.products by 24 %}
{% for product in collection.products %}
{% render 'product-card', product: product %}
{% endfor %}
{% endpaginate %}
Keep snippets focused. If a product card snippet renders multiple badges, reviews, metafields, swatches, and app hooks on every collection page, it can become expensive very quickly.
Avoid Unnecessary Redirects
Redirect chains add time before the page can even start loading.
Check for:
- HTTP to HTTPS redirects
- Non-www to www redirects
- Old product URLs
- Tracking URLs
- App-generated redirects
- Internationalization redirects
One redirect is sometimes unavoidable. Chains are not.
For the general concept behind server response time, check our guide on how to reduce server response time. Just remember that Shopify does not give you the same server-level controls as a custom stack.
Optimize Third-Party Scripts
Third-party scripts are often the hidden reason Shopify stores feel slow.
The most common third-party scripts include:
- Google Tag Manager
- Google Analytics
- Meta Pixel
- TikTok Pixel
- Pinterest tags
- Klaviyo
- Review platforms
- Chat widgets
- Loyalty apps
- A/B testing tools
- Heatmaps
- Session recording tools
- Affiliate tracking
Each third-party script can add DNS lookups, TLS negotiation, JavaScript execution, layout changes, and main-thread work.
Audit Third-Party Scripts in the Waterfall
Open a waterfall chart and look for:
- Scripts loading before the LCP element
- Long JavaScript tasks
- Domains that appear on every page
- Duplicate analytics libraries
- Old pixels from removed campaigns
- App scripts that load where the app is not visible
- Chat or popup scripts that run before the page is usable
Do not assume every marketing script is required. Ask whether it is still actively used.
Use Google Tag Manager Carefully
GTM makes it easy to add tags. It also makes it easy to forget tags.
Review your GTM container regularly:
- Remove unused tags.
- Avoid duplicate pixels.
- Fire tags only on relevant pages.
- Avoid triggering everything on page view.
- Delay non-critical tags until after consent or user interaction where appropriate.
If you cannot explain why a tag exists, it probably should not be running on every page.
Worker-Based Approaches
Tools such as Partytown can move some third-party scripts to a web worker. This can reduce main-thread pressure, but compatibility varies.
Use this carefully on Shopify. Some scripts expect direct access to the DOM, cookies, events, or synchronous browser APIs. Test analytics accuracy, consent behavior, cart flow, and app behavior before relying on a worker-based setup.
Shopify Speed Optimization Checklist
Use this checklist when optimizing a Shopify store:
- Test the home page, product pages, collection pages, cart page, and important landing pages.
- Test mobile performance first.
- Identify the actual LCP element for each template.
- Do not lazy load the LCP image.
- Use responsive Shopify image output with correct
sizesand widths. - Add image width and height attributes.
- Use WebP/AVIF-friendly image delivery where supported.
- Remove unused Shopify apps.
- Check for leftover app code after uninstalling apps.
- Load app scripts only where needed.
- Delay non-critical JavaScript.
- Keep product page JavaScript small.
- Reduce unused CSS.
- Load CSS conditionally by template or section where practical.
- Reduce font families and weights.
- Replace icon fonts with SVG icons where possible.
- Reserve space for reviews, recommendations, banners, and widgets.
- Avoid hero sliders.
- Remove old tracking pixels.
- Audit Google Tag Manager.
- Reduce redirects.
- Simplify heavy Liquid templates.
- Monitor real-user Core Web Vitals after deployment.
Common Shopify Speed Optimization Mistakes
Installing More Apps to Fix App Bloat
This is the classic Shopify performance trap.
A store becomes slow because of too many apps, then another app is installed to "speed it up". Sometimes optimization apps help, but they cannot fully undo a bloated app stack.
Start by removing unnecessary work.
Lazy Loading the LCP Image
Lazy loading below-the-fold images is good. Lazy loading the hero image or main product image is usually bad.
This is one of the most common Shopify LCP issues.
Using Huge Hero Sliders
Hero sliders are rarely worth the performance cost.
They often load multiple large images, JavaScript, CSS, navigation controls, and animation logic. Most users see only the first slide.
Use one strong hero section instead.
Loading All App Scripts Globally
If a reviews app is needed only on product pages, loading it on every collection and landing page is wasteful.
Global loading is convenient for apps, but it is not always good for performance.
Relying Only on Desktop Lighthouse
Desktop Lighthouse can hide mobile problems.
Mobile users are usually more affected by JavaScript execution, image size, and layout shifts. Always test mobile.
Ignoring Real-User Core Web Vitals
A lab test can pass while real users still struggle.
Use lab tools for debugging and RUM for long-term monitoring. This is especially important for Shopify stores because apps and marketing scripts often change after the initial optimization work.
If you want to understand the difference between page-level and origin-level field data, our article on field data vs origin summary is a useful reference.
Replacing a Theme Without Auditing Apps
Theme replacement can help, but it is not a full performance strategy.
If your store still loads the same apps, pixels, popups, reviews, chat widgets, and third-party scripts, the new theme may not improve Core Web Vitals much.
Audit apps first, then decide whether the theme is still the main bottleneck.
Summing Up
Shopify speed optimization is mostly about reducing unnecessary work.
You want fewer apps, fewer scripts, cleaner Liquid, optimized images, a faster LCP element, fewer layout shifts, lighter fonts, and better control over third-party code.
Do not treat Shopify page speed as a one-time project. Stores change constantly. New apps get installed, campaigns add pixels, themes get edited, and product pages become heavier over time.
The practical workflow is simple:
- Test important pages with SpeedVitals.
- Identify the actual bottlenecks.
- Remove unnecessary apps and scripts.
- Optimize images and the LCP element.
- Reduce JavaScript and CSS.
- Fix layout shifts.
- Monitor real-user Core Web Vitals over time.
If you keep that process in place, your Shopify store will be much easier to keep fast, stable, and conversion-friendly.
