Shopify Store Slow on Mobile? How to Find the Real Cause
Diagnose a slow Shopify store on mobile: read Core Web Vitals, find heavy apps and scripts, fix the hero image and fonts, then re-test in a sensible order.
In this guide
Key takeaways
- Judge speed by Core Web Vitals on mobile (LCP 2.5 seconds or less, INP 200 milliseconds or less, CLS 0.1 or less), not by one Lighthouse score.
- The usual suspects are third-party code (apps, tags, chat and review widgets) and a hero image that loads late, rather than Shopify itself.
- Test the home, collection, product and cart pages separately, and change one thing at a time in a duplicate theme.
- Fix the largest image first: do not lazy-load it, size it for the screen and give it high fetch priority.
A Shopify store is usually slow on mobile for three reasons: too much JavaScript from apps and tracking tags, a hero image that loads late, and theme code that blocks rendering. Shopify’s own platform is rarely the bottleneck. The fix is to measure the right pages, work out which of those three is hurting you, and change one thing at a time. This guide shows the order I use.
Start with what Google actually measures
Google judges page experience with three Core Web Vitals, measured on real visits and reported separately for mobile and desktop:
- Largest Contentful Paint (LCP) is how long the biggest visible element takes to appear. Good is 2.5 seconds or less.
- Interaction to Next Paint (INP) is how quickly the page responds to taps and clicks. Good is 200 milliseconds or less.
- Cumulative Layout Shift (CLS) is how much the layout jumps while the page loads. Good is 0.1 or less.
Each metric is assessed at the 75th percentile of visits, so a handful of fast visits cannot hide a slow majority. Google documents the thresholds on web.dev. INP replaced First Input Delay as a Core Web Vital in 2024, so older advice about FID is out of date.
There are two kinds of numbers, and mixing them up causes most of the confusion:
- Field data comes from real Chrome users over the previous 28 days. PageSpeed Insights shows it at the top of the report as the Core Web Vitals assessment, and Search Console groups it by URL. This is the data Google uses.
- Lab data is one simulated load on a throttled phone. It is the Lighthouse score. It is repeatable, which makes it good for testing a fix, but it is not what your visitors experienced.
Shopify now shows field data in the admin as well. Its web performance reports use real visitor data for LCP, INP and CLS, with a summary on the Themes page and the full reports under Analytics. Shopify retired its older Lighthouse-based speed score, so any guide that tells you to chase that number is out of date. Password-protected and brand-new stores often have no field data at all, and in that case lab tests are all you have.
Test the pages that carry the revenue
Do not test only the home page. A Shopify theme renders a different template for each page type, and apps often load on some templates and not on others. Test at least these:
- The home page.
- Your busiest collection page.
- Your busiest product page, with a variant selected if you sell variants.
- The cart, or the cart drawer once it is open.
Use PageSpeed Insights, or Lighthouse in Chrome DevTools in an incognito window so extensions cannot skew the result. Run each page three times and keep the median, because single runs vary. Write the numbers down. You will need them to see whether a change helped.
Lab tests for mobile simulate a mid-range phone on a slow connection, which is deliberately harsh. If a page is slow there but fine on your laptop, that gap is the finding. Code that runs well on a fast laptop CPU is the same code that makes a mid-range phone stall.
Find the heavy parts: apps, scripts and tags
On most slow Shopify stores I look at, the largest single cost is JavaScript that someone added for a good reason: reviews, popups, chat, upsells, loyalty, a tag manager with thirty tags. Each one is small. Together they decide whether a phone can respond in 200 milliseconds.
To see what is loading:
- Open the page in Chrome, open DevTools and go to the Network tab. Tick Disable cache and reload.
- Sort by Size, then by Time. Tick 3rd-party requests to hide your own files and Shopify’s.
- Note every domain that is not yours or Shopify’s. Each one is a vendor your store depends on.
- In the Performance tab, record a page load and look for long tasks, which Chrome marks in red. Click one to see which script caused it.
- Open the Coverage panel from the DevTools command menu to see how much JavaScript and CSS the page downloads but never uses.
Apps that add an embed to your theme can be switched off in the theme editor under App embeds. Switch one off in a duplicate of your theme, test again, and you know what it costs. Apps that wrote code straight into your theme files when they were installed are harder to spot. Search the theme code for the app’s name, and for domains in <script src> tags. Leftovers from apps you uninstalled long ago are common, and they keep loading even though the app is gone. For a step-by-step review of every app, with an audit sheet you can copy, see how to audit Shopify apps that slow down your store.
Tag managers need the same scrutiny. Open Google Tag Manager and ask, for each tag, who uses the data and when someone last looked at it. Tags for ad platforms you stopped using are pure cost. If your tracking needs a proper review, the GA4 tracking audit for Shopify covers what to keep.
This table maps what you see to the usual cause:
| What you see | Likely cause | First thing to try |
|---|---|---|
| Main image appears late (high LCP) | The image is lazy-loaded, oversized or discovered late | Load it eagerly, add fetchpriority="high", serve the right width |
| Page jumps while loading (high CLS) | Images or embeds without dimensions, banners and widgets that load late | Set width and height, reserve space for late content |
| Taps and filters feel laggy (high INP) | Too much JavaScript running on the main thread | Remove or delay scripts, trim cart drawer and filter code |
| Fast on Wi-Fi, slow on a phone | JavaScript volume that a mid-range CPU struggles with | Test with CPU throttling, cut third-party code |
Make the first image load fast
On product and landing pages the LCP element is almost always an image: the hero, or the first product photo. The Lighthouse report names it in the Largest Contentful Paint element audit. Then check three things.
- It is not lazy-loaded. Lazy loading is for images below the fold. Delaying the one visitors see first makes the page slower. Some themes and customizations lazy-load the hero by mistake.
- It is the right size. A 3000-pixel photo sent to a 390-pixel-wide phone wastes bytes. Give the browser a
srcsetand asizeshint so it can choose. - It is discovered early. Mark the LCP image with
fetchpriority="high"so the browser fetches it first.
In Liquid, the image_tag filter accepts any HTML attribute, so this looks like:
{{ section.settings.hero_image
| image_url: width: 1600
| image_tag:
loading: 'eager',
fetchpriority: 'high',
widths: '480, 768, 1024, 1600',
sizes: '100vw',
alt: section.settings.hero_image.alt
}}
Setting names differ between themes, so adapt the first line to yours. The pattern is what matters. Everything else, such as the second product photo, thumbnails and the footer logo, can stay lazy.
To prevent layout shift, every image needs a width and height, which image_tag adds for you. Every banner, app block or embed that appears late needs reserved space, for example a minimum height on its container.
Check theme code and fonts
Theme-level problems show up as render-blocking requests and long tasks:
- Scripts without
defer. A script in the<head>withoutdeferorasyncstops the page from rendering until it has downloaded and run. Your own theme scripts should usually usedefer. For third-party snippets, check the vendor’s documentation for an async or deferred option. - Components that load everywhere. Sliders, mega menus and popups often ship their JavaScript and CSS to every page. Load heavy components only on the templates that use them.
- An oversized DOM. Thousands of nested elements, common with page builders, make every style recalculation slower. Lighthouse flags an excessive DOM size.
- Too many fonts. Each family and weight is another file. Two families with two weights each is plenty for most stores. Use
font-display: swapso text shows right away. Thefont_facefilter takes afont_displayoption for this.
If a third-party widget can wait, let it wait. Chat and review widgets rarely need to load before the visitor interacts:
<script>
// Load the chat widget on the first interaction, or after five seconds.
(function () {
var loaded = false;
function load() {
if (loaded) return;
loaded = true;
var s = document.createElement('script');
s.src = 'https://chat-vendor.example/widget.js'; // use your vendor's script URL
s.async = true;
document.head.appendChild(s);
}
['pointerdown', 'keydown', 'scroll'].forEach(function (type) {
window.addEventListener(type, load, { once: true, passive: true });
});
setTimeout(load, 5000);
})();
</script>
Check with the vendor that delayed loading is supported, and test that the widget still works. Some need to run early to catch the first message.
Fix things in a sensible order
Work in a duplicate of your live theme and re-test the same pages after every change. This is the order that usually pays off fastest:
- Remove what you do not use. Leftovers from uninstalled apps, old tags, duplicate analytics and unused sections.
- Fix the LCP image on your main templates.
- Delay or replace heavy third-party scripts. Chat, popups, review carousels and loyalty widgets are the usual candidates.
- Reserve space for anything that appears late, to cut layout shift.
- Trim theme JavaScript, especially cart drawers, filters and sliders that run on every page.
- Check real-user data a month later. Field data is a 28-day window, so look at Search Console’s Core Web Vitals report then, not the next day.
Keep a log with the date, the change and the before-and-after numbers. When something regresses, which it will after the next app install, the log tells you where to look.
If you also run a WooCommerce store, the causes are different. Why WooCommerce checkout and admin get slow covers that side.
If you are speeding up a store before a big sale, the Black Friday readiness checklist shows where this work fits in a three-week plan.
When it is worth bringing in help
Removing leftovers and fixing the main image is work most store owners can do. Bring in a developer when:
- The slow code lives in a heavily customized theme and you are not sure what is safe to remove.
- Several apps write into the theme, and removing one breaks another.
- INP is the failing metric. It usually means changing JavaScript, not changing settings.
- You are up against a deadline, such as a sale or a theme migration.
Performance work was part of my role on the Cosmo Together Shopify Plus store, which you can read about in selected work. If that sounds like your store, send me the store address and a line or two about the symptoms. I will reply with what I think is causing it and what I would check first.
Common questions
What is a good PageSpeed score for a Shopify store?
There is no single number to chase. The PageSpeed score is a lab measurement, while Google uses real-user Core Web Vitals. Aim for good LCP, INP and CLS in the field data, and use the lab score to compare before and after a change. A store can pass on real-user data with a modest lab score, and the reverse.
Do Shopify apps slow down my store?
They can. Many apps add JavaScript, CSS or network requests to every page, and some leave code behind after you uninstall them. Switch an app's embed off in a duplicate theme and compare results to see what it costs.
Should I lazy-load all my images?
No. Lazy-load images below the fold. The image visitors see first, usually the hero or the first product photo, should load eagerly and with high fetch priority.
How long until Search Console shows an improvement?
Field data is a rolling 28-day window, so expect to wait about four weeks before the Core Web Vitals report fully reflects a change. Lab tests show the effect straight away.