help1
shopify page speedshopifypage speed insightspsiperformance

Shopify Page Speed: What's Inside Minimize Main-Thread Work

The shopify page speed warning labeled Minimize main-thread work points at files you cannot delete. Here is the slice you actually can.

help1 Team
Shopify Page Speed: What's Inside Minimize Main-Thread Work

Open PageSpeed Insights. Run the mobile test on your store. Scroll to the Diagnostics panel and click the arrow next to Minimize main-thread work. A table unfolds with three categories: Script Evaluation, Style and Layout, and Garbage Collection. Script Evaluation is almost certainly the big one. Under it sits a list of files that look like you should be able to delete. Most of them, you cannot. This is the chase I ran on my own shopify page speed report, in the order I actually ran it, including the dead ends.

What I checked first

I started where the warning pointed. In my Script Evaluation list, in rough order of execution time: theme.min.js, vendors.js, a Klaviyo CDN URL, a Tidio CDN URL, a Judge.me URL, and a Google Tag Manager container. Estimated savings somewhere between two and six seconds depending on which rerun I ran. The instinct was to work top-down. Delete the biggest offender first.

I opened the theme editor and found theme.min.js in assets/. On a duplicated theme, I removed the reference to it in theme.liquid. The variant selector stopped working. The cart drawer refused to open. Add-to-cart technically still worked, but the page just full-reloaded. I put the reference back.

So the biggest line in my Script Evaluation list was a file I could not remove. This is where every one of these investigations starts: at the top of the Script Evaluation list, assuming the heaviest file by weight is the one to kill first. On a Shopify store, it almost never is.

Why nothing on the list could go

The next five entries told the same story in different shapes. vendors.js is whatever framework-adjacent code the theme ships with. The Klaviyo URL is served from static.klaviyo.com, which I do not control. Tidio is served from code.tidio.co. Judge.me is served from cdn.judge.me. Each of those arrives on my page because an app has an active App Embed, each App Embed is routed by Shopify through the content_for_header Liquid tag in theme.liquid, and that tag's output is a black box generated server-side on every page load.

I did try the obvious thing. I searched theme.liquid for the string tidio. Nothing. For klaviyo. Nothing. The scripts arrive on the page without any theme-level reference I can edit. That is by design. The merchant-facing surface for pruning them is the Theme Editor's App Embeds panel: a list of toggles, one per installed app, with no visibility into the script each one injects.

I pulled up a Shopify partner's reply from an October 2025 Community thread as a sanity check and found the line I expected: "Code injected via content_for_header shouldn't be modified by merchants." Fine. The flag in my hand pointed at files whose removal path was "remove the app." That is not a technical fix. That is a product decision. Most shopify page speed advice on YouTube stops here, which is where the warning starts to feel personal.

Where the trail went cold

Deferred loading was the next obvious lever. Load the chat widget after a user scrolls, load the review widget after the viewport sees it, delay the popup script to requestIdleCallback. Several threads recommend this. The theoretical argument is solid: if the script does not execute in the critical path, it does not count toward Total Blocking Time in the shopify page speed simulation.

I almost did it. Then I read what the vendors themselves say about deferred loading. Tidio, Gorgias, and Shopify Inbox do not ship deferred loading as a native option. If you force it with a custom script, you break the early-visitor-identification that is the whole reason the chat widget was installed in the first place. The visitor who should have triggered the proactive message now does not. The attribution window that fires an abandoned-cart email now has a gap. That is a tradeoff worth considering, but it is not free. I filed deferral under "ask a developer" and moved on.

Speed-optimiser apps were the other dead end. The accepted advice loops back to installing something like TinyIMG or an auto-optimiser, with the implication that it will reduce main-thread execution. These apps cannot touch app CDN scripts; the main-thread column is not what they optimise. I had already run this trial a year earlier on a different store and watched the number not move.

The clue I almost missed

I almost closed the tab there. What I almost missed was a smaller entry buried further down the Script Evaluation list. A URL whose domain I did not recognise. It had been there for months. I did not have an active app for it. I did not have an App Embed with that name. The app was gone; its code was not.

This is the one slice of main-thread work on a shopify page speed report that is both actionable and safe for a non-developer merchant. Orphaned code from already-uninstalled apps. The confusion comes from a technical distinction most merchants are never told: scripts injected through content_for_header are removed automatically when the app is uninstalled, but scripts an app hardcoded into theme.liquid or into a snippet during setup are not. Those stay. An August 2026 Shopify Community thread on script isolation methodology spelled this out explicitly - search for <script tags that live outside the content_for_header block, inside your theme files, and delete the ones that belong to apps you no longer run.

The clearest empirical sense of how much of your main-thread work is apps versus the theme itself comes from a January 2023 Community thread. A merchant tested the same Warehouse theme on their populated production store and on an empty test store with no apps installed. The populated store returned 380ms TBT. The empty store returned 62ms. The theme accounted for 62ms. The remaining 318ms was apps. On most reports I have looked at, that ratio holds. You cannot touch most of that 318ms without removing an app. You can touch the slice that belongs to apps that no longer exist.

I found three such orphans on my store. Two were from apps I had uninstalled a long time ago. One was from a tag manager setup I had replaced and never fully cleaned up. Deleting those is the one category of main-thread work that is both safe and free.

Why the mobile number is almost always worse

Here is a thing about shopify page speed numbers that nobody tells you up front: PSI's mobile test and its desktop test are not the same device run through different throttles. They are a Moto G Power on Slow 4G against your actual browser, and the gap between them is often ten times. One merchant in a November 2023 Community thread posted a store with 0-50ms TBT on desktop and 370-1,400ms TBT on mobile - the same store, the same scripts, the same page load. The lab is doing the amplification.

That matters because the Minimize main-thread work time estimate is calibrated to the simulated device. The scripts that cost 50ms on your laptop cost roughly four times that in that simulation. Real user field data from Google Search Console is almost always kinder than the lab report. If you have Core Web Vitals data in Search Console, pull up your actual INP numbers before deciding how much time to spend hunting down a widget. A r/shopify study of 269 stores from August 2026 included an example where the lab TBT read 510ms and the real-user INP for the same page read 130ms. The lab was a story about one device class under one network condition. The field was the actual customer base.

I say this as somebody who has spent several evenings trying to beat a mobile score that no real visitor was actually experiencing.

The GTM I could not find in theme.liquid

Then there was Google Tag Manager. GTM was the single biggest Script Evaluation contributor on my store, bigger than any individual app CDN script. The r/shopify 269-store study found one store where GTM alone cost 329ms of script evaluation, more than all of that store's own first-party code combined. I expected to find a GTM tag somewhere in my theme. There was no GTM reference in theme.liquid. No custom pixel in Settings > Customer events. I had never, as far as I could remember, pasted a GTM container ID into anything.

This confused me for an afternoon. The answer surprised me: the Google & YouTube sales channel injects a GTM container into every storefront page automatically, with zero reference to GTM anywhere in theme code. A February 2024 Community report described the exact same situation: a merchant running only the Google & YouTube sales channel, no manual GTM setup, no custom pixels, found GTM as the biggest third-party blocker on their store at roughly half a second of execution time.

The fix path lives outside the theme, inside the Google & YouTube channel settings and, in some cases, inside GTM itself. If GTM shows up as a dominant main-thread contributor on your shopify page speed report and you cannot find it in your theme code, this is where to check. On my store, the Google channel had been configured years ago and I had never audited which tags were still active inside the GTM container itself. There is an asymmetry worth naming: inside the GTM container, you can prune individual tags. Across installed apps, you cannot prune individual scripts.

What I actually changed, and what it did

By the end of a few hours of this, here is what I had done:

  1. Deleted the orphan <script tags from theme.liquid and files under snippets/ that belonged to apps I had uninstalled long ago. I backed up the theme first.
  2. Opened GTM and paused tags that were still firing from pixels I had already moved elsewhere.
  3. Confirmed that two of my tracking apps (Meta Pixel, GA4) were already running through Shopify's Web Pixels API, which lives in a sandboxed worker and does not appear in the main-thread Script Evaluation list at all. Two other tracking integrations had not migrated and still showed up there.

Here is what I did not do: remove any of the apps whose scripts were flagged. The chat widget stayed. The review widget stayed. Klaviyo stayed. Each one was earning its keep somewhere else in the funnel, and my shopify page speed number is not the metric I run the business on.

PSI's estimated savings on Minimize main-thread work came down by a few hundred milliseconds. The mobile Performance score moved by a point or two. On real-user field data from Search Console, I could not see a difference above measurement noise - which is roughly what the research threads warn you to expect, because the lab test is a story about a Moto G Power on Slow 4G and most of my customers are not.

The thing I regret spending time on was looking for a magical theme-level fix for scripts the theme does not own. The thing I was glad I spent time on was reading the Script Evaluation list carefully enough to spot the single URL that did not belong to any installed app. That is where the honest work on this warning sits.

What this leaves me with

If you are staring at this warning right now and want a second pair of eyes on which script in your Script Evaluation list is actually removable versus structural, 15 free minutes with a help1 expert is usually enough time to walk the breakdown together and sort them. For the sibling PSI warning that measures payload bytes rather than execution time, we keep a companion piece at Chasing the Shopify Unused JavaScript Warning - different metric, mostly the same offenders.

I have not tested the Web Pixels API migration on Shopify Plus; your mileage may vary there. And the custom-script-deferral approach that some developers recommend for chat widgets is real, but it quietly breaks the early-visitor-identification that is the whole reason you installed the widget. I do not recommend it without a developer in the room.

Minimize main-thread work on Shopify is one of those warnings that teaches you more about Shopify's architecture than it does about speed.

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.