
A Hyvä migration usually delivers what it promises: a much lighter JavaScript footprint than Luma, faster Time To Interactive, and a meaningful Core Web Vitals improvement out of the gate. The win is real. But the win is also not permanent. Most Hyvä storefronts pick up bloat over time, and the JavaScript footprint that started at 30 to 50 kilobytes of first-party code can drift to 200 kilobytes or more within a year if nobody is watching.
The drift is invisible until it shows up in Interaction to Next Paint, the metric Google added to Core Web Vitals in 2024 that measures how responsive a page feels when users actually tap things. INP regression is the most common post-migration performance issue we see on Hyvä stores. A storefront that scored well on initial migration measurement scores poorly six months later, and the team cannot figure out why. The answer is almost always JavaScript that was added without being measured.
This piece is the audit framework we use to find and remove that bloat. It is not glamorous work. It is also the highest-ROI performance work available on a mature Hyvä storefront, and most teams skip it because it does not feel like building.
What you are actually looking for
The audit is hunting four categories of bloat. The first is dead first-party code, meaning custom JavaScript that was written for a feature that no longer exists or for an A/B test that ended six months ago. The second is duplicated third-party code, which usually shows up as two analytics libraries or two personalization tags doing roughly the same job. The third is heavyweight Alpine.js components that exceed what Alpine was designed for and should have been Hyvä compiled or moved server-side. The fourth is render-blocking scripts in the head that should have been moved to async or defer loading.
You need to look for all four because they compound. A page can be slow because of one large script or because of 12 small ones. The audit produces the same kind of evidence either way: a list of every script the page loads, ranked by impact, with a recommendation per item.
The web.dev guide to INP is the right shared vocabulary for talking about INP-driven JavaScript audits with the team. The metric is more sensitive to bloat than LCP was, which is why the audit discipline matters more in 2026 than it did in 2023.
Tools that work
You do not need a dozen tools. You need three, used consistently.
The first is Chrome DevTools Performance and Coverage panels. Performance gives you the flame chart of what is executing on the main thread. Coverage tells you what percentage of each loaded script is actually used. Run Coverage on your top three page types in incognito mode with cache disabled, and you will immediately see the scripts that are loading 100 percent of their bytes but using 15 percent of their code.
The second is Lighthouse in CLI mode, run against the production storefront from a synthetic environment. Lighthouse gives you the rolled-up scores, but the more useful output is its specific opportunities like “remove unused JavaScript” and “reduce the impact of third-party code.” Treat those opportunities as the audit’s leading list of suspects.
The third is your Real User Monitoring data, which tells you what is happening on real devices in the wild. The synthetic results from DevTools and Lighthouse will identify candidates. RUM tells you which candidates are actually hurting users. Bemeir’s preferred RUM pattern is to capture INP attribution data, which tells you specifically which scripts and which interactions are causing the worst INP percentile measurements.
Step one: enumerate every script on the page
Start with a simple inventory. On your highest-traffic page types, list every script the page loads. For each script, record the source domain, the size in kilobytes, the loading attribute (async, defer, blocking), and the apparent function.
You will be surprised at how long the list is. A typical Hyvä storefront with even modest third-party tooling loads 15 to 30 scripts per page. The exercise of writing them all down is itself useful. You will see immediately that you have two heat-mapping tools, three analytics tags doing roughly the same job, and a personalization library that nobody on the team remembers turning on.
The table below is the format we use. It is deliberately mechanical, because the point of the inventory is comprehensiveness.
| Script source | Loading | Size (kb) | Function | Action |
|---|---|---|---|---|
| gtag.js | async | 88 | Analytics | Keep |
| connect.facebook.net | async | 64 | Pixel | Keep |
| analytics2.example.com | blocking | 142 | Analytics | Remove duplicate |
| chatwidget.example.com | defer | 156 | Live chat | Move to lazy load |
| heatmap1.example.com | async | 198 | Session recording | Remove duplicate |
| custom-promo.js | blocking | 14 | Promo countdown | Remove if no active promo |
This inventory by itself often reveals 30 to 50 percent of the bloat without any deeper analysis. The scripts that are obviously redundant or obviously dead get removed first. That alone produces a measurable performance improvement that justifies the rest of the audit.
Step two: pull the unused code numbers
Once the inventory is clean, run Coverage in DevTools against the same page types. Each remaining script will show a percentage of unused bytes. Sort the list by unused-byte total in kilobytes, not percentage. A 200 kilobyte script that is 40 percent unused is contributing more dead weight than a 50 kilobyte script that is 80 percent unused.
The unused-byte numbers tell you two things. First, which scripts are candidates for tree-shaking or splitting. Most of the time the answer to “why is this script 80 percent unused” is that the script is a generic SDK that exposes a lot of functionality but the page only uses a fraction. Tree-shaking is rarely possible in third-party scripts, but it is often possible in first-party Hyvä bundles. The webpack and Vite documentation on tree-shaking is useful reference if your team is building custom Alpine components or Hyvä modules from source.
Second, which scripts should be loaded only when needed. The chat widget that loads on every page but only matters once a user clicks the chat icon is a textbook lazy-load candidate. The deferred loading patterns Hyvä supports natively make this easier than it was on Luma, but the discipline still has to be applied. The Hyvä documentation on script loading and the broader web.dev guide to lazy loading cover the relevant patterns.
Step three: profile INP attribution
Once the inventory is clean and the obvious unused code is removed, profile actual user interactions on production. Chrome DevTools can record an interaction profile by clicking around the page with the Performance panel recording. The flame chart will show which scripts are running when a user taps a button, opens a menu, or adds to cart.
The INP attribution data, ideally captured in production via RUM, will tell you the same story across real users. The pattern you are looking for is a third-party script that runs synchronously in response to an interaction, blocking the main thread for 200 milliseconds or more. Common offenders are analytics tags that fire on every click and personalization libraries that recompute on every interaction.
The fix for these is usually one of three options. Move the script to a Web Worker if it does not need DOM access. Debounce the script’s interaction handlers so it does not fire on every click. Or remove the script entirely if the business value does not justify the user experience cost. Bemeir has had a lot of conversations with marketing teams about the third option, and the conclusion is usually that the script can be removed once we share the measured INP impact alongside the measured marketing value.
Step four: audit your own Hyvä components
After the third-party audit, audit your custom Hyvä components. The pattern we see most often is that a developer built an Alpine.js component for a piece of UI that exceeded what Alpine was designed for. Alpine is great for small declarative interactions. It is not great for state-heavy components with deep reactivity graphs. Hyvä’s compile-time alternative, hyva-compiled, exists for this reason.
Look for any Alpine component that exceeds 200 lines of declarative markup, that manages more than a handful of reactive state values, or that performs significant computation on initialization. These are candidates for either compile-time rendering, server-side rendering via a Magento block, or extraction into a more appropriate small JavaScript component.
The Alpine.js documentation on performance considerations explicitly notes the patterns Alpine is good and bad at. Read it once with your team and use it as the shared vocabulary for which existing components belong on Alpine and which should be moved off it.
What we typically find
In a typical Hyvä audit, Bemeir’s team identifies between 80 and 250 kilobytes of removable first-party and third-party JavaScript per page. The largest categories, in order, are duplicate analytics or session recording tools, dead A/B test infrastructure, oversized chat widgets that should lazy-load, and custom Alpine components that have grown beyond their design intent.
The performance impact, measured against a baseline taken before the audit, is typically a 20 to 40 percent reduction in Total Blocking Time and a 30 to 60 millisecond improvement in INP at the 75th percentile. LCP usually improves too, by a smaller amount, because removing render-blocking scripts in the head pulls forward the time when the LCP image starts loading.
The work is one to two sprints per audit, with most of the time going to coordination with marketing and product teams about which scripts to remove or move. The technical work itself is fast. The political work of getting the green light to remove a script that someone added six months ago is the slow part. We typically anchor those conversations in the measured performance cost alongside the measured business value, which makes the discussions empirical rather than emotional.
If your storefront migrated to Hyvä more than 12 months ago and has not been audited, you almost certainly have at least one full sprint of cleanup available. The audit is the cleanup. Bemeir’s Adobe Commerce performance practice runs this exercise as part of standard quarterly reviews on any client engagement that includes performance ownership. If you are also running Shopify Plus or BigCommerce storefronts, the framework translates with minor adjustments. The discipline is what counts. The platform-specific details are the easier part.





