Almost every speed conversation I have starts with a screenshot of a red number from PageSpeed Insights, usually with the question "why is my Shopify PageSpeed score so low on mobile when the store loads fine on my phone?" Both statements can be true at the same time. The score is a simulation of a slow phone on a slow network, and your own phone on home wifi is neither. Knowing what that test measures is the difference between fixing real problems and chasing a number.
What your Shopify PageSpeed score is actually simulating
When you paste your URL into PageSpeed Insights, the "Diagnose performance issues" section is a Lighthouse run, a lab test. Lighthouse loads your page once, from a Google data center, using an emulated mid-range phone with heavy CPU throttling and a slow-4G-class connection. It then turns what it saw into a score from 0 to 100.
Two things follow from that. First, the mobile score punishes JavaScript far more than the desktop score does, because a throttled CPU takes a long time to parse and run scripts that a laptop chews through instantly. Total Blocking Time carries the largest weight in the score, and on Shopify stores it is almost always driven by apps and tracking scripts rather than by the theme. Second, the result is a single run. Rerun the same URL three times and you will often get three different numbers.
Lab data vs field data: which Shopify PageSpeed score matters
You will see at least three different "speed" views, and they do not agree with each other:
- PageSpeed Insights, lab section. The simulated Lighthouse run described above. Useful for diagnosing, unreliable as a pass/fail grade.
- PageSpeed Insights, "Discover what your real users are experiencing". This is field data from the Chrome User Experience Report (CrUX): real Chrome users on your real pages, aggregated over the previous 28 days and judged at the 75th percentile. This is the data Google's page experience signals are based on. If your store is new or low-traffic, this section may be empty.
- Shopify's Online Store Speed report. Shopify's own Lighthouse-based score for your home page, a top product page and a top collection page. It is a lab-style score, so it moves around like PSI does, and it is also affected by which theme and apps are live.
My rule is simple: use lab data to find what to fix, and use field data to decide whether you have a problem. A store with a mobile lab score of 52 whose field data passes all three Core Web Vitals is in better shape than a store with a lab score of 85 and a failing LCP in the field. The thresholds for a "good" result are LCP at or under 2.5 seconds, INP (Interaction to Next Paint) at or under 200 milliseconds, and CLS (Cumulative Layout Shift) at or under 0.1.
Reading the PageSpeed Insights opportunities honestly
The "Opportunities" and "Diagnostics" lists are generated automatically, and they are not a to-do list in priority order. A few of them deserve skepticism:
- "Estimated savings" are not additive. Fixing three items that each claim 0.4 seconds will not take 1.2 seconds off your load time.
- "Reduce unused JavaScript" often points at your theme's own bundled files. Some of that is unavoidable, and rewriting a theme's asset pipeline for a marginal gain is rarely worth it.
- "Reduce the impact of third-party code" is the one I read first. It lists each third-party domain with its blocking time and transfer size, which is a ready-made map of which apps and pixels are costing you.
- "Largest Contentful Paint element" names the element that counts as your LCP. Optimize that one first.
The real culprits on Shopify stores
When I audit a store, these are the usual suspects, roughly in the order I check them:
- App embeds and script tags. Reviews widgets, popups, upsell bars, chat bubbles and loyalty programs each add JavaScript, and many load on every page even if they are only used on one.
- An unoptimized hero or LCP image. A banner uploaded at 4000 pixels wide and served to a phone, or one that is lazy-loaded when it should be prioritized.
- Third-party pixels, often through Google Tag Manager. Meta, TikTok, Google Ads, a heatmap tool and an affiliate script, all firing at once. Duplicates are common when the same pixel is installed through both GTM and the sales-channel integration.
- Sliders and autoplay video. A rotating homepage carousel downloads every slide up front. A background video above the fold can become your LCP element.
- Too many homepage sections. Fifteen sections, each with its own images and scripts, is a lot for a mobile browser.
- Fonts. Three font families in multiple weights, loaded from an external host, block text rendering or cause it to jump.
- Render-blocking theme JavaScript. Scripts in the head without
defer, or heavy theme features (mega menus, predictive search, quick view) loading on pages that never use them. - Layout shift from late-loading banners. An announcement bar, cookie notice or "free shipping" banner injected after first paint pushes everything down and tanks CLS.
Finding which app costs how much (and the code left behind)
An app's marketing page will not tell you its cost, so measure it:
- In the theme editor (Online Store > Themes > Customize), open the App embeds panel in the left sidebar. This lists every app that injects code through Shopify's app embed system.
- Run PageSpeed Insights on a duplicate theme or a preview link a few times and note the typical result.
- Toggle one embed off, save, and test again. Repeat for each one. The apps that move total blocking time or LCP noticeably are your expensive ones.
- For scripts you cannot toggle, open Chrome DevTools, go to the Network tab, right-click a request and choose "Block request domain", then reload and compare in the Performance panel.
Always do this on a duplicate theme, never the live one. Then ask a blunt question about each expensive app: is it earning more than it costs in speed?
Leftover app code after you uninstall
This one surprises people. Uninstalling an app from Settings > Apps removes its app embed and most script tags, but older apps wrote code directly into your theme: a snippet in the snippets/ folder, a {% render %} line in theme.liquid, a stylesheet reference, or extra lines in a product template. That code stays behind, still requesting files from a server that may no longer respond.
To check, go to Online Store > Themes > Edit code and search the whole theme for the app's name or its domain. Remove references from a duplicate theme first, preview it, and publish only once the storefront looks right.
Images, LCP and the fetchpriority trap
On most stores the LCP element is the hero image on the homepage or the main product image on a product page. Shopify's CDN will resize and convert images for you, but only if your theme asks for the right sizes. In Liquid, that means using the image_url filter with a width and passing it to image_tag, with a sensible sizes attribute so phones do not download a desktop-sized file:
- Request a width that matches the layout, for example
{{ image | image_url: width: 1200 }}, and let the srcset offer smaller options. - Add
loading: 'lazy'to images below the fold. - Do the opposite for the LCP image: no lazy loading, and add
fetchpriority: 'high'so the browser fetches it early. Lazy-loading your hero is one of the most common causes of a slow LCP, and it is easy to do by accident when a theme applies lazy loading to every image.
Fonts, sliders and layout shift
For fonts, use one family, two weights if you can manage it, and Shopify's own font library or a self-hosted file. In Liquid, the font_face filter accepts font_display: 'swap' so text shows immediately in a fallback font, and you can preload the main file in the head.
For sliders, ask whether a single strong image would do the job. If so, you have removed a library and several image requests in one move. If you keep a carousel, only the first slide should load eagerly.
For layout shift, reserve space. Give images explicit dimensions or an aspect ratio, and make sure an announcement bar has a fixed height before its content loads. A CLS above 0.1 almost always traces back to one of those two things.
Realistic expectations, and when to hire help
Do not chase 100
A store with a dozen apps, a review widget, a loyalty program and several pixels will rarely hit 90 on mobile, and that is fine. Scores shift from run to run and when Lighthouse updates, and a lab score does not directly set your rankings. What matters is that field data passes Core Web Vitals and that pages feel quick to real shoppers.
A good outcome is a few expensive items removed or deferred, a prioritized hero image, a trimmed homepage, and field metrics inside the thresholds. If you are already there and still staring at an orange 68, spend the next hour on product pages and content instead. My Shopify SEO checklist covers where else the effort pays off.
When it makes sense to hire help
You can do the app-by-app testing yourself, and I encourage it. Bring in a developer when the cause is in the theme code (render-blocking scripts, a leftover app that is hard to trace, a heavy section that needs rebuilding) or when removing an app means replacing its function with a lighter custom solution. That is the work covered by my website speed optimization service, and my Shopify development work covers rebuilds when a theme is beyond saving. I start with an audit so you know what each fix is worth first.
If you would like a second pair of eyes, send me your store URL and I will tell you honestly whether your numbers are a real problem or just a noisy score.
FAQ
Why is my Shopify PageSpeed score lower on mobile than on desktop?
The mobile test emulates a mid-range phone with a heavily throttled CPU and slow network, so JavaScript from apps and tracking scripts costs far more time than it does in the desktop test. The same store can easily score 40 points lower on mobile.
What is a good Shopify PageSpeed score?
Lab scores of 50 to 80 on mobile are common for stores with several apps. A better target is passing Core Web Vitals in real-user data: LCP at or under 2.5 seconds, INP at or under 200 milliseconds and CLS at or under 0.1.
Do Shopify apps slow down my store?
Many do, because they add JavaScript and CSS to every page. The cost varies widely by app, so toggle each app embed off one at a time on a duplicate theme, retest, and compare to see which ones cost the most.
Does uninstalling an app remove all its code?
Not always. Apps that use app embeds clean up after themselves, but older apps may leave snippets, render tags or script references in theme.liquid. Search your theme code for the app's name or domain to find and remove them.
