You install a Shopify app in two clicks. Reviews, a popup, a chat widget, an upsell. Each one solves a real problem, so you keep adding them. Six months later your store runs fifteen apps and your mobile pages feel sluggish. The thing is, you never see the bill. The cost is hidden in JavaScript that loads on every page, on every visit, for every visitor.
That cost is real. It shows up in your Core Web Vitals, in your bounce rate, and eventually in your revenue. Google has spent years documenting how loading speed maps to conversion. Akamai found in 2017 that a 100ms delay in load time could cut conversion rates by 7%. Deloitte showed in 2020 that improving mobile site speed by a tenth of a second lifted retail conversions by 8.4%. These are not abstract numbers. They are the price of every script you let run.
The hard part is that you cannot manage what you do not measure. Most store owners have no idea which app costs them what. They suspect the chat widget is heavy, but they cannot prove it, so they leave everything on. This article gives you a method to put a number on each app, a matrix to decide what stays and what goes, and a 30-minute audit you can run yourself today.
If you haven't read my article on INP, read it first, it sets the Core Web Vitals context.
The invisible cost of Shopify apps
Most Shopify apps work the same way. They inject an external script into your theme, usually a single tag that points to a file hosted on the app vendor's servers, not yours. That one tag looks harmless in your code. Behind it sits a chain of work your visitor's browser has to complete before the app does anything useful, and every link in that chain costs time.
The chain starts with a DNS lookup. Your visitor's browser sees a new domain it has never contacted on this page, so it has to ask a DNS server for the IP address behind that domain. That round trip can take anywhere from a few milliseconds on a fast connection to a couple hundred on a congested mobile network. You pay this cost once per unique domain per visit, and a store running a dozen apps from a dozen vendors forces a dozen separate lookups before any of those scripts even start downloading.
Then comes the connection itself. Once the browser knows the IP, it opens a secure connection, which means a TLS handshake. On top of the basic TCP setup, TLS adds its own back-and-forth to negotiate encryption keys before a single byte of the actual script can travel. On a high-latency mobile connection, each handshake to a fresh origin can add real delay, and again, you pay it per new vendor domain. This is why connecting to many third-party origins is slower than serving everything from one, even when the total file size is identical.
Only after DNS and TLS does the script download. Then the browser has to parse it, compile it, and execute it, and most of that happens on the main thread. The main thread is the single lane where your browser handles layout, painting, and responding to taps and clicks. While it is busy parsing and running an app's JavaScript, it cannot respond to your visitor. That is the mechanism behind a page that looks loaded but freezes for a beat when someone taps a button.
The impact lands on three metrics. Largest Contentful Paint suffers when scripts compete for bandwidth and block the rendering of your hero image or main text. Interaction to Next Paint suffers when heavy JavaScript keeps the main thread busy, so taps and clicks feel delayed. Total Blocking Time, which you see in lab tests, measures exactly that main-thread congestion. One app rarely breaks a page. Ten apps together can push a mobile store from a passing grade to a failing one.
The trickier issue is unused code. An app that handles product reviews still loads its full script on your homepage, your cart, your checkout, even though there are no reviews to show there. A lot of the JavaScript shipped to a given page is never actually run on that page. You can verify this directly in your browser. Open Chrome DevTools, go to the Coverage tab, record a page load, and you will see exactly which bytes of each script were used and which were dead weight, usually shown as a red bar next to a green one. The web.dev guide on optimizing INP explains why that idle JavaScript still hurts: parsing and compiling it costs main-thread time even when the code never executes.
So the real cost of an app is not just its feature. It is the DNS lookups, the connections, the bytes downloaded, and the main-thread time spent on code that often does nothing on the page in front of your customer. None of that appears on an invoice, which is exactly why it goes unmanaged for so long. To manage it, you need to turn each app into a measurable number.
The decision matrix
You cannot decide which apps to remove based on a feeling. You need two axes: how much business value the app delivers, and how much performance it costs. Put them together and you get a simple grid that tells you what to do with every app in your stack.
| | LOW perf cost | HIGH perf cost | |------------------|---------------|----------------| | HIGH value | Keep | Optimize | | LOW value | Keep or fine | Remove |
The top-left cell is the easy win: high value, low cost. Think of a lightweight analytics tag or a well-built upsell that drives real revenue without dragging your pages down. These apps earn their place and barely register on your performance budget, so they need no further attention. Keep them and move on to the cells that actually require a decision.
The top-right cell is where the work happens: high value, high cost. A reviews app that genuinely lifts conversion but ships a heavy script falls here, and so does most of your stack's real weight. You do not remove these, because the business would feel the loss. You optimize them instead. Defer their loading, restrict them to the pages that need them, or move to a lighter alternative that does the same job. This cell is where a careful audit pays for itself, because the gains are large and the feature stays intact.
The bottom-left cell is harmless: low value, low cost. An app you barely use that happens to be light, a small badge, a tracking pixel that fires once. It does not move the needle in either direction, so it is not worth your energy. Keep it or remove it on a whim, but do not spend an afternoon agonizing over it. The matrix exists to keep you out of this corner.
The bottom-right cell is the obvious cut: low value, high cost. The popup you installed for one campaign and forgot, the chat widget nobody answers, the loyalty program with three members. These are pure overhead, paying a real performance tax for a feature your store does not use. Remove them first. They are the fastest wins you will find, and removing them tends to free up more headroom than owners expect.
Now, how do you measure the cost axis with real numbers? The method is straightforward and it works for any app.
- Run PageSpeed Insights on a representative page (your homepage and a product page) and note the LCP, INP, and CLS. This is your baseline BEFORE.
- Disable the app from your Shopify admin, or remove its script from the theme on a duplicate test theme.
- Run PageSpeed Insights again on the same page. This is your AFTER.
- The delta on LCP, INP, and CLS between BEFORE and AFTER is the real performance cost of that app.
Test one app at a time so you can attribute the change correctly. Use a duplicate theme so your live store is never affected during testing. Once you have a delta for each app, you can place every one of them on the matrix with confidence instead of guessing.
The 3 app categories that hurt the most
Across the stores I audit, three categories show up again and again as the heaviest. They are popular for good reason, but they are also the usual suspects when a mobile store starts failing its Core Web Vitals. The pattern is consistent enough that you can usually predict the culprits before you even open DevTools.
Reviews
Review apps like Loox, Judge.me, Yotpo, Stamped, and Okendo are valuable. Social proof sells, and a strong wall of reviews on a product page can be the difference between a sale and a bounce. The problem is that many of them load a full JavaScript bundle, image galleries, and star-rating widgets on every page, including pages with no reviews to display.
The symptom is easy to spot. You open the Coverage tab on your homepage and find a large review script sitting there mostly unused, because there is nothing for it to render. On a product page that script earns its weight. On your homepage, collection pages, and cart, it is dead weight competing for the same main thread your hero image needs.
The light fix is to restrict the review script to the templates that actually show reviews, typically the product page and any dedicated reviews section. From there, lazy-load the widget so it only loads when the visitor scrolls near it, since reviews usually sit well below the fold. Many of these apps expose a setting for both behaviors, and where they do not, you can scope and defer the script directly in the theme.
Marketing popups
Popup and email-capture apps like Privy, OptiMonk, Justuno, and Wisepops are designed to interrupt, which means they often load early and aggressively. That early load is the whole point of the product, but it puts the script in direct competition with the content your visitor actually came to see.
The symptom here is twofold. First, the script tends to run during the initial load when the main thread is already at its busiest. Second, popups and sticky bars frequently inject content with no reserved space, so the page jumps as they appear and your CLS takes the hit. A visitor reaching for a button can find it shoved down half a second after the page looks ready.
The light fix is to delay the popup script until after the page is interactive, because a popup that fires three seconds in loses nothing by loading three seconds late. Reserve fixed space for any sticky bar so its arrival shifts nothing. And be honest about value: if a popup converts at a fraction of a percent, it belongs in the remove cell of the matrix, not the optimize cell.
Chat widgets
Chat widgets like Tidio, Crisp, Intercom, and Gorgias are some of the heaviest scripts on a typical store. They load a full chat runtime, open websocket connections, and inject an iframe, often on the very first page load, before the visitor has shown any intention of talking to you.
The symptom is a large, persistent third-party payload that appears on every page and a chunk of main-thread time spent setting up a connection most visitors will never use. In the network panel you see the widget reaching out to its vendor's servers and holding a live connection open in the background, quietly taxing every session.
The light fix is to load the chat widget on user intent. Show a lightweight static button first, styled to look exactly like the real launcher, and only load the full chat runtime when the visitor actually clicks it. This single change can remove a large chunk of JavaScript from your initial load while keeping the feature fully available to anyone who wants it. The handful of visitors who open chat barely notice the half-second it takes to spin up.
Real case: Mabonatur, Spanish Shopify store, +42% on mobile
Mabonatur is a Spanish Shopify store in the natural health sector. They came to me with a familiar problem: the store worked, the catalog was solid, but mobile performance was dragging. Their mobile Core Web Vitals were failing, and on a store where most traffic is mobile, that translates directly into lost sales.
The diagnosis was the pattern this whole article describes. The store had accumulated a stack of apps and a theme that, together, shipped far too much JavaScript to the browser on every visit. The main thread was congested, the page felt slow to respond, and the layout was shifting as elements loaded in. It was not one catastrophic problem, it was the compound weight of many small ones, none of which had ever been measured.
So we measured. I ran the app stack through the decision matrix, app by app, using the before-and-after method to put a real performance cost on each one. That turned a vague sense of slowness into a concrete priority list: which scripts to defer, which to scope down to specific pages, and which to remove entirely. Nothing was cut on a hunch, and nothing valuable was touched without a plan to keep its feature working.
From there the work was methodical. We optimized font loading so text rendered fast without blocking. We fixed the carousel that was causing layout shift, stabilizing the page as it loaded. We lazy-loaded the non-critical widgets so they no longer competed for the main thread during the initial load. In parallel, we ran a technical SEO refactor, because a faster, cleaner store is also a more crawlable one, and the two efforts reinforce each other.
The point I want to make is that none of this was guesswork. Every decision came from a measurement. The matrix kept us focused on the apps that mattered and stopped us from wasting time on the ones that did not, which is exactly how you keep a project like this from sprawling into a month of busywork.
The published result was performance optimization and technical SEO that delivered a +42% improvement on mobile. That came from the combination of a disciplined app audit, targeted performance fixes, and the parallel SEO work, all driven by data rather than assumptions.
See the Mabonatur case on my portfolio.
DIY audit of your app stack in 30 minutes
You can run a first pass on your own store in about half an hour. You will not catch everything an in-depth audit would, but you will find your worst offenders and you will know more than 90% of store owners do about their own stack. Use a duplicate theme for the testing steps so your live store stays untouched.
List all your apps
Open your Shopify admin and write down every installed app. Next to each one, note what it actually does for your business. Most owners are surprised by how many apps they are running and how many they had forgotten about.
Ask the question for each app
For every app, answer two things. Does this drive real value (revenue, conversion, retention)? And is it worth a performance cost? This sets up the value axis of your matrix before you measure anything.
Measure the PageSpeed Insights baseline
Run PageSpeed Insights on your homepage and a product page. Record the mobile LCP, INP, and CLS. These numbers are your reference point. Everything you change from here is measured against this baseline.
Disable candidate apps
Start with the apps you suspect are heavy or low value. On a duplicate test theme, disable one app at a time. Testing one at a time is what lets you attribute each change to a specific app.
Re-measure after each disable
After disabling an app, run PageSpeed Insights again on the same pages. The delta on LCP, INP, and CLS is that app's real performance cost. Write it down next to the value note from step two.
Decide
Place each app on the matrix using your value note and your measured cost. Keep the cheap and valuable ones, optimize the costly-but-valuable ones, and remove the costly low-value ones. Then re-enable on your live store only what you decided to keep.
Apps: fewer, better, measured
The goal is not to strip your store down to nothing. Some apps earn their keep many times over, and removing them would cost you sales. The goal is to know the price of each one and pay it on purpose. Fewer apps, better chosen, and every one of them measured against a real number rather than a hunch.
Once you have run the matrix, you will usually find a handful of easy removals, a few candidates to optimize, and a clear sense of what your store actually needs. That alone tends to recover meaningful mobile performance, and mobile performance is where most of your traffic and most of your lost conversions live. The discipline also pays off later: the next time an app catches your eye, you have a method to test it before it quietly settles into your load and stays there for a year.
If you want to go deeper on the metric that app JavaScript hits hardest, read my article on INP. And if you are weighing whether to run this kind of audit yourself or bring in help, the DIY vs expert breakdown will help you decide. Either way, start by measuring. You cannot fix a cost you have never put a number on.




