Chasing the Shopify Unused JavaScript Warning to Its Sources
The shopify unused javascript warning in PageSpeed Insights names files most merchants cannot touch. Here is what I found when I chased mine down.

Open PageSpeed Insights. Type in a Shopify URL. Scroll to Opportunities. About four out of five stores I look at show the same red bar at the top of that section: Eliminate unused JavaScript, with an estimated savings somewhere between 400ms and several seconds. Underneath it, a stack of file names: theme.min.js, vendors.js, something on cdn.shopify.com, something on cdn.hextom.com, maybe storefront-banner.js. The instinct is to open the theme editor and start deleting. Do not do that yet. I spent a while chasing this exact warning on my own store, and almost none of the files it pointed at were the thing to remove.
The shopify unused javascript warning is the most misinterpreted line item in the whole PSI report. This post is the chase I ran through mine, in the order I actually ran it, including the dead ends.
What I checked first
The first two names on my list were theme.min.js and vendors.js. Both live in the theme's assets/ folder. I opened the theme editor, went to Online Store > Themes > Edit code, duplicated the theme, and stared at those two files. They were the biggest thing on my list by kilobyte weight. If I could just cut some code out of them, the warning would shrink.
I tried the smallest possible test: I temporarily disabled the reference to theme.min.js in theme.liquid on a duplicate theme, then loaded the storefront. The variant picker went silent. Add-to-cart still worked, but the cart drawer never opened. The header search modal did nothing. Filters on the collection page reloaded the whole page instead of updating in place. Everything that felt like "the store" was gone.
I put the file back and went looking for what parts of it I could safely trim. This is where I met the first honest voice on the topic, a developer post from 2021 about the Debut theme: "optimizing theme.js is one of the to-dos. Trust me, it's not easy, i've spent hours and I'm nowhere near done." That was a working developer saying it out loud. I closed the file.
Why theme.min.js and vendors.js were not the answer
The important thing I did not understand at first is what "unused" actually measures. PSI's coverage tool loads the page on a simulated mobile device and watches which lines of JavaScript actually execute during the initial render window. Any code that loads but does not execute in that window gets marked unused. Not unnecessary. Not deletable. Unused, as in did-not-fire, in the first few hundred milliseconds.
Almost every function inside theme.min.js fires in response to something a user does later. Click the variant selector. Open the cart drawer. Type in the search bar. Filter a collection. That code is loaded up front because if it were not, the interaction would stall while the browser fetched it on click. It also does not run during the first render, so it registers as unused. Both things are true at the same time. It is exactly what a theme should do, and PSI counts it as a problem.
Once I understood that, the two biggest files on my list stopped being targets. They were doing their job. I moved on.
Where the trail went cold
The next name on the list was cdn.hextom.com/js/ultimatesalesboost.js. I had never heard of a company called Hextom. I searched my installed apps and did not immediately find it. It turned out to be Hextom: Ultimate Sales Boost - the app powering the free-shipping countdown bar on my cart page. The CDN hostname was the only clue, and it did not obviously map to the app name in the app listing.
This is a bigger problem than it looks. On the same audit I found three more unfamiliar hostnames. One turned out to be a review widget's assets server. One was a translation app I had installed and forgotten about. The third I only identified after copying the URL into DevTools and watching which script tag on the page had inserted it. Merchants running into shopify unused javascript reports on the community forums describe the same fingerprint every time: a hostname they cannot place, a script they did not knowingly add, and no idea whether removing it will break checkout or a cart drawer they need.
The trail went cold here for a while. I could not act on scripts I could not name. So I went back to the storefront HTML, opened DevTools, and started tracing each unfamiliar script tag back to the app that had inserted it. It took me about forty minutes across seven or eight apps. That is time I would rather not repeat. It is also the only way I know to close this gap: an app is only removable if you can identify what it does for you first.
The clue I almost missed
Halfway through that list, I found a script tag referencing a review app I had uninstalled more than a year earlier. The app was gone from my installed list. Its scripts were still being loaded on every page, from the app vendor's CDN, because someone on my team had at some point pasted the install snippet directly into theme.liquid instead of using the app embed. Uninstalling the app removed the app embed. It did not touch the manually pasted snippet.
This is the piece of shopify unused javascript that is almost always actionable, and it is the piece merchants miss most often. Open theme.liquid in the code editor. Search for anything that looks like a <script> tag with an external src, an install marker like <!-- start Klaviyo --> or <!-- Yotpo Reviews -->, or an {% include %} / {% render %} referencing a file that no longer exists in your snippets. Compare the app names in those comments to your currently installed apps. Whatever is orphaned, remove it. Do the same pass on theme.liquid, product.liquid, and any custom section files a former developer touched.
On the store I was auditing, that pass removed roughly 60KB of scripts on every page. It also fixed a small stream of JavaScript errors I had been ignoring in the console for months. The PSI unused JavaScript number went down by a real amount that came from real removed code, though nowhere close to the "estimated savings" PSI had promised.
If you are stuck on the orphaned-code pass and cannot tell whether a snippet is safe to delete, that is exactly the kind of judgment call help1's expert chat exists for. Duplicate the theme first, share the snippet, and get a second opinion before you commit.
What the unused label actually is
By the time I finished my trace, my running list looked like this:
- Two Shopify-owned platform scripts, including
storefront-banner.js, that I have no way to modify. Shopify Support has repeatedly declined to address the flag on these for other merchants; there is no lever here. - Two theme bundles that would break the store if I touched them.
- Six app CDN scripts, each of which loads on every page whether the page uses the app or not.
- One block of orphaned code in
theme.liquidfrom an uninstalled app. Actionable. - One script I had added manually years ago to
theme.liquid, that only needed to run on product pages. Actionable, with a{% if template contains "product" %}wrapper.
That distribution is representative of what I see on other stores. Most of the payload is the two categories where I have no lever: platform scripts and current app scripts. The pieces I can actually remove are orphans and manually added script tags. The {{ content_for_header }} replace-filter workaround that gets recommended in half the community threads is not one I trust; a developer in one of those threads called it "very unstable and can't support app changes," and I have seen that go silently wrong on my own themes after routine app updates. If an app uses the ScriptTag API, no amount of Liquid conditionals in the theme will keep the app's script from loading everywhere.
The lever that actually moves the number
Once I accepted that only one category was really under my control on a store-by-store basis, the question simplified: which apps do I actually need loading on every single page? On the store I was auditing I had seven active apps whose scripts appeared in the report. Two of them were driving revenue in a way I could see in analytics. Two were arguably useful. Three I could not remember why I installed. I uninstalled the three. The PSI number on the next audit dropped by more than the orphaned-code pass had achieved.
This is the finding merchants keep arriving at the hard way in the community threads: app delta is bigger than theme delta. The phrase comes from a comment on a 204-audit study that ran Lighthouse across 17 popular themes; the specific number is not what matters, the direction is. Adding a stack of apps to a clean theme costs more speed than the theme's own overhead in almost every case. Removing an app is the single lever that reliably moves the shopify unused javascript number.
I would not recommend an "app that removes unused JavaScript." I have never seen one of those work in a way that survived a re-audit two weeks later. Most of them either defer scripts (which just shifts when PSI measures them) or run detection tricks against the PageSpeed bot. Merchants on Reddit spot these within hours; the top-voted reply in one such thread was, verbatim, "this is basically just an advert for an expensive app." Any tool that promises to eliminate the shopify unused javascript flag without removing an actual app is worth reading skeptically.
For the same reason, I do not chase 100/100 on PSI anymore. What matters for SEO is the field data Google collects from real Chrome users, not the lab score PageSpeed shows in the interface. If Core Web Vitals are green for real visitors, I stop optimizing. The lab number is diagnostic, not a target. If you want the longer version of that argument, I wrote about it in the page-speed floor apps cannot cross.
What I do about it now
My checklist for a fresh shopify unused javascript audit on a store I have not seen before, in the order I run it:
- Duplicate the theme.
- Open
theme.liquid,product.liquid, and any custom section files. Look for orphaned<script>tags and install comments from apps that are no longer in the installed apps list. Remove what is clearly orphaned. If a snippet is ambiguous, leave it and note it. - List every installed app. Cross-reference each app to a specific business outcome I can point at (a channel converting, a support flow it powers, a legal requirement). Any app that fails the cross-reference goes on the uninstall list.
- Uninstall the flagged apps one at a time. Re-audit after each. The point of one at a time is that a rare app leaves theme cruft behind on uninstall; catching it takes seeing the delta cleanly.
- Ignore everything on the PSI list that lives on
cdn.shopify.comor maps totheme.min.jsandvendors.js. That is not the fight.
The whole pass usually takes under an hour on a small store. Most of that hour is on step 3, not step 2 - the decision about which apps stay is harder than any Liquid edit.
Shopify unused javascript is one of those PSI warnings that sends merchants after the wrong file over and over, while the answer that actually moves the number lives in the installed apps list.
Still stuck? Talk to an expert.
Our vetted Shopify experts can fix this issue for you in a live session. $39 per session. Your first 15 minutes are free.