Founder & Lead Engineer, RAITHub
A slow Shopify store is usually slow because of what has been added to it, not Shopify itself: app scripts that block rendering, a heavy theme, oversized or lazy-loaded hero images, and Liquid loops that delay the first byte. Check your web performance report first. Google's targets are LCP within 2.5 seconds, INP of 200 ms or less, and CLS of 0.1 or less.
This guide is for store owners and developers who have a slow store and want to know where the time goes before paying anyone to fix it. Shopify puts it plainly: "each feature that you add to your online store can impact your store's web performance" (Shopify Help: store speed). The job is to find which features cost the most and deal with those first.
How do you know if your Shopify store is actually slow?
Look at the three Core Web Vitals, measured on real visitors, rather than a single speed score from one test run. Google's definitions and "good" thresholds, measured at the 75th percentile of page loads, are (web.dev: Web Vitals):
| Metric | What it measures | Good | Usual Shopify cause when it fails |
|---|---|---|---|
| LCP, Largest Contentful Paint | How fast the main content, often the hero image, appears | 2.5 seconds or less | Lazy-loaded or oversized hero image, render-blocking app scripts, slow Liquid |
| INP, Interaction to Next Paint | How quickly the page responds when someone taps or clicks | 200 ms or less | Too much JavaScript from apps and the theme running on the main thread |
| CLS, Cumulative Layout Shift | How much the page jumps around while it loads | 0.1 or less | Images without dimensions, app widgets and banners injected late, web fonts swapping |
Shopify's admin has a web performance dashboard that reports these three metrics from "real user data from the past 30 days". It keeps 90 days of history, data can be up to 36 hours behind, and it only fills in when your store is not password-protected (Shopify Help: web performance dashboard). The same page notes that the reports show how changes such as "app installs, theme updates, and new code" affect your storefront, which makes it the first place to check when a store suddenly got slower.
Which metric fails tells you where to look. A poor LCP points at images, scripts and server time. A poor INP points at JavaScript. A poor CLS points at things arriving late and pushing content around.
Are my apps slowing down my Shopify store?
Often, yes. Apps that add something to your storefront, such as reviews, upsells, pop-ups, chat, loyalty or tracking, usually do it with JavaScript, and many load it early. Shopify's theme performance guide tells theme developers to "remove render-blocking apps" that block HTML parsing before content renders (Shopify: theme performance best practices).
Three patterns cause most of the damage:
- Scripts that block the page. A plain
<script src>in the page head stops the browser from building the page until the script downloads and runs. - Several apps doing overlapping jobs. Two review apps, three tracking pixels, a pop-up app and a chat app each bring their own code and often their own copy of shared libraries.
- Code left behind. An app that was installed years ago may have added snippets directly to theme files. Uninstalling the app does not always remove that code, so it keeps loading, sometimes pointing at files that no longer exist. This is general engineering experience rather than a Shopify statement, so check your own theme files.
How do you find which app is the slow one?
Measure one change at a time on a copy of your theme.
- Duplicate the live theme and work on the copy, so customers see no change.
- List every third-party script the page loads. In Chrome DevTools, open the Network panel, filter by JS, and sort by size. Anything not served from your store or Shopify's CDN is a candidate.
- Turn off app embeds one at a time in the theme editor on the copy, and run the same test after each change on the same page and device profile.
- Search the theme code for app names and script domains to find hard-coded leftovers from removed apps.
- Write down the difference each app makes, then decide with the numbers in front of you whether its feature is worth the time it costs.
Is my Shopify theme the problem?
It can be, in two ways: what it sends to the browser and how long its Liquid takes to render on Shopify's servers. For context, Shopify requires a minimum Lighthouse performance score of 60 for a theme to be accepted into its Theme Store (Shopify: theme performance best practices), so a theme from there has passed a basic bar, but customisation and apps can drag it far below that.
The most common server-side cause, according to Shopify's performance guide, is deeply nested Liquid loops, which it calls the most common cause of high time to first byte and notes can scale quadratically. Reading metafields inside a loop creates the same pattern. A collection page that loops over every product, and inside that over every variant and every metafield, gets slower as the catalogue grows, even if nothing else changes.
On the browser side, look at how much JavaScript the theme ships before anyone interacts. web.dev's advice for INP is to "do as little work as possible" in event handlers and to break long work into separate tasks, so the page can respond between them (web.dev: optimise INP). A theme that runs large scripts on every page makes that impossible, whatever the apps do.
Are images slowing down my store?
Usually the hero image is, because it is typically the LCP element. web.dev is direct about the most common mistake: "Never lazy-load your LCP image, as that will always lead to unnecessary resource load delay" (web.dev: optimise LCP). Shopify's theme performance guide adds the rest: use the image_url and image_tag filters, lazy-load only images outside the first screen, mark the LCP image with fetchpriority="high", always give images a width and height, and use srcset and sizes.
In Liquid, that looks like this. The first image is the hero; the second is a product card further down the page.
{%- comment -%} Hero: the likely LCP element. Load it early, never lazily. {%- endcomment -%}
{{ section.settings.hero_image
| image_url: width: 1600
| image_tag:
widths: '480, 800, 1200, 1600',
sizes: '100vw',
loading: 'eager',
fetchpriority: 'high',
alt: section.settings.hero_image.alt }}
{%- comment -%} Product cards below the fold: lazy-load, smaller sizes. {%- endcomment -%}
{{ product.featured_image
| image_url: width: 600
| image_tag:
widths: '300, 450, 600',
sizes: '(min-width: 990px) 25vw, 50vw',
loading: 'lazy',
alt: product.featured_image.alt }}
The image_tag filter writes the width and height from the image itself, which stops the layout shift that images without dimensions cause. The widths list lets a phone download a 480-pixel image instead of a 1,600-pixel one.
How do you stop scripts from blocking the page?
Load them later. Shopify's guide recommends defer or async on scripts that are not needed for the first render, and loading some JavaScript only when the visitor interacts, through a dynamic import() inside an event listener.
<!-- Blocks the page while it downloads and runs: avoid in the head -->
<script src="{{ 'size-guide.js' | asset_url }}"></script>
<!-- Downloads in parallel, runs after the page is parsed -->
<script src="{{ 'size-guide.js' | asset_url }}" defer></script>
<!-- Loads only if the visitor opens the size guide -->
<script>
document.querySelector('[data-size-guide]')?.addEventListener('click', async () => {
const { openSizeGuide } = await import({{ 'size-guide.js' | asset_url | json }})
openSizeGuide()
}, { once: true })
</script>
The last pattern needs size-guide.js to be written as an ES module that exports openSizeGuide. For app scripts you do not control, the choice is simpler: keep the app, ask the app's developer whether it can load later, or remove it.
What order should you fix things in?
Start with the changes that cost least and move the failing metric most. This order suits most stores:
| Step | What to do | Effort | Metric it usually moves |
|---|---|---|---|
| 1 | Remove apps you no longer use, and their leftover theme code | Low | LCP, INP |
| 2 | Stop lazy-loading the hero image; add fetchpriority="high" | Low | LCP |
| 3 | Serve responsive images through image_tag with widths and sizes | Low to medium | LCP, CLS |
| 4 | Defer non-critical scripts; load rarely used features on interaction | Medium | LCP, INP |
| 5 | Reserve space for banners and app widgets that appear late | Medium | CLS |
| 6 | Rewrite nested Liquid loops and move metafield reads out of loops | Medium to high | LCP (through server time) |
| 7 | Replace apps that are slow but needed with lighter options or custom code | High | All three |
After each step, wait for the real-user data to catch up before judging the result. Shopify's dashboard can lag by up to 36 hours and reports a 30-day window, so a lab test is the quicker check and the dashboard is the proof.
When is slowness a sign you have outgrown your setup?
Rarely. Most slow stores get fast inside Shopify. It is worth a wider look only when the slow parts are features your business depends on and no lighter version exists, or when workarounds for missing features are what fill the page with apps. Shopify's limitations and when to go custom covers the platform walls, and Shopify vs custom ecommerce compares the options. A custom front end is not automatically faster; why a Next.js app is slow in production shows how a custom build can hit the same problems.
Why RAITHub for this
- Diagnosis before changes. The method above, measuring one change at a time, is how RAITHub approaches any performance problem: name the cause, then fix it, then prove it with numbers.
- Performance work in production. TheSkinProof, the founder's own marketplace venture rather than a client project, uses edge caching, content-addressed image caching and active cost tuning across its hosting. It is a custom Next.js platform, not a Shopify store.
- Fixed scope. A free 15-minute technical audit, then a written fixed quote with its assumptions. You own the result; an NDA is standard.
When you don't need us
- The fix is a theme setting or a single app. A Shopify theme specialist will usually be quicker and cheaper for Liquid and theme-editor work. RAITHub is not a Shopify theme studio.
- You can remove the app yourself. If step 1 of the table fixes your numbers, you are done.
- Your theme developer is still available. Ask them first; they know the code.
If the cause is custom code, an integration or a front end built outside the theme, start from the fix one issue page, or send the problem with your web performance report and book the free 15-minute audit. More on ecommerce builds is on the ecommerce industry page.
Last reviewed: 29 September 2026. Shopify and web.dev documentation checked on 29 September 2026.
Frequently asked questions
Why is my Shopify store so slow?
Usually because of added features rather than Shopify itself: app scripts that block rendering, a heavy or heavily customised theme, a hero image that is oversized or lazy-loaded, and nested Liquid loops that slow the server's first response.
Do Shopify apps slow down my store?
Many do, especially apps that add storefront features with JavaScript. Shopify's own performance guide tells theme developers to remove render-blocking apps. Test each app's cost by turning its app embed off on a duplicate theme.
What are good Core Web Vitals for a Shopify store?
The same as for any site: LCP within 2.5 seconds, INP of 200 milliseconds or less, and CLS of 0.1 or less, measured at the 75th percentile of real page loads on mobile and desktop.
Where can I see my Shopify store's Core Web Vitals?
In the web performance dashboard in the Shopify admin. It reports LCP, INP and CLS from real user data over the past 30 days, keeps 90 days of history, and can lag by up to 36 hours.
Does uninstalling an app remove its code?
Not always. Apps that added snippets directly to theme files can leave that code behind. Search your theme for the app's name and script domains after uninstalling, and remove what is left on a duplicate theme first.
Should I lazy-load all images on my Shopify store?
No. Lazy-load images below the first screen, but never the hero or other LCP image. Give that one fetchpriority="high" so the browser fetches it early.
Related posts
Ready to discuss your project?
Book a free 15-minute technical audit with our engineering team.