> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vortexiq.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Unused JavaScript, Website Performance (PageSpeed + CrUX)

> Unused JavaScript for Website Performance (PageSpeed + CrUX) stores. Tracked live in Vortex IQ Nerve Centre. How to read it, why it matters, and how to act...

**Metrics type:** [Supporting Metrics](/nerve-centre/overview#metrics-types-explained)  •  **Category:** [Website Performance](/nerve-centre/connectors#connectors-by-type)

## At a glance

> **JavaScript bytes downloaded but not executed during the page load**, ranked per script. Lighthouse's Coverage analysis identifies which lines of JS code never ran during the audit; the bytes occupied by those lines are "unused JS". **Brands routinely ship 50-70 percent of their JavaScript bundle on every page, with only 30-50 percent actually executing.** The unused bytes still cost: download time, parse time, and memory. Removing them via code-splitting and tree-shaking is a structural performance improvement that compounds across every page-view.

|                                        |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **What it counts**                     | Per JS resource: total bytes downloaded, bytes covered (executed), bytes wasted (downloaded but never run). Lighthouse uses Chrome's Coverage API to instrument which lines fired during the audit; the difference between downloaded and covered is "unused".                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| **Sample type**                        | **Lab data** from a single Lighthouse audit. Reflects what didn't execute during the synthetic page load; pages with rich user interaction (filter widgets, modals, dynamic content) may execute more JS in real use than lab measures.                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| **Why bundles accumulate unused code** | (1) **Frameworks and libraries ship more features than any single page uses**: jQuery includes selectors, animations, AJAX, deferred utilities; a homepage may use 20 percent of jQuery. (2) **Polyfills for older browsers** ship even to modern browsers that don't need them. (3) **Dead code from removed features** stays in the bundle if not actively cleaned. (4) **Per-page features bundled site-wide**: cart-drawer JS shipped on every page including pages without cart action. (5) **Third-party scripts ship full SDKs** when only specific functionality is used.                                                                                                                  |
| **Common ecommerce patterns**          | (1) **jQuery on Stencil sites**: 84KB total, \~64KB unused per page typically. (2) **GTM container**: 56-200KB depending on tag count, much unused per page-load. (3) **Klaviyo SDK**: 180KB total, only popup + behavior tracking active on most pages (\~80-100KB unused). (4) **A/B testing tools**: full variant fetcher loaded even on pages without active tests.                                                                                                                                                                                                                                                                                                                            |
| **Optimisation playbook**              | (1) **Code-splitting**: webpack/Rollup/esbuild can split a single bundle into per-page chunks; each page only loads its own JS. Estimated savings: 30-60 percent of JS bytes. (2) **Tree-shaking**: removes unused exports automatically with modern bundlers. Requires ES module imports; cuts library size 20-40 percent. (3) **Dynamic imports**: load heavy widgets (modal libraries, chart libraries) only when triggered. (4) **Defer non-critical bundles**: even unused-on-this-page JS doesn't need to block render. (5) **Library swaps**: replace heavy libraries with lighter alternatives (Moment.js → date-fns saves \~80KB; jQuery → vanilla JS or modern alternatives saves 84KB). |
| **The diminishing-return curve**       | First 50 percent of unused JS is usually trivial to remove via code-splitting. Next 30 percent requires more work (auditing third-party SDKs, lazy-loading widgets). Last 20 percent is structural (rewriting the bundling architecture). **Most merchants stop at 60-70 percent removal**; the marginal effort beyond that exceeds marginal benefit.                                                                                                                                                                                                                                                                                                                                              |
| **Currency**                           | n/a, this is a list of byte-savings opportunities.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| **Time window**                        | `T` (current state).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| **Alert trigger**                      | `top entry > 100KB unused` (red), `> 50KB unused` (amber).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| **Sentiment key**                      | `null`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| **Roles**                              | owner, operations                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |

## Calculation

Calculated automatically from your Website Performance (PageSpeed + CrUX) data. See the At a glance summary above for what the metric tracks and the worked example below for a typical reading.

## Worked example

A UK-based BigCommerce fashion store homepage audit, mobile, Wednesday 15 May 26.

|                 Rank | Resource                       | Total bytes | Used bytes |    Unused |   Coverage % | Recommendation                                   |
| -------------------: | ------------------------------ | ----------: | ---------: | --------: | -----------: | ------------------------------------------------ |
|                    1 | `gtm.js` (GTM container)       |       184KB |       42KB |     142KB |          23% | Quarterly GTM audit; remove unused tags          |
|                    2 | `klaviyo-sdk.js`               |       178KB |       64KB |     114KB |          36% | Lazy-load popup component                        |
|                    3 | `tidio-chat.js`                |       148KB |       38KB |     110KB |          26% | Defer entirely to post-load                      |
|                    4 | `jquery-3.6.0.min.js`          |        84KB |       22KB |      62KB |          26% | Long-term: replace with vanilla JS for new code  |
|                    5 | `stencil-bundle.js` (theme JS) |       132KB |       78KB |      54KB |          59% | Code-split by template type                      |
|                    6 | `optimizely.min.js`            |        96KB |       28KB |      68KB |          29% | Lazy-load only when test is active for the page  |
|                    7 | `hotjar-recording.js`          |        84KB |       24KB |      60KB |          29% | Sample 10% of sessions instead of 100%           |
|                    8 | `meta-pixel-base.js`           |        32KB |       18KB |      14KB |          56% | Acceptable; conversion tracking has thin profile |
| **Total JS shipped** |                                |   **938KB** |  **314KB** | **624KB** | **33% used** |                                                  |

What the ranked list is telling us:

1. **66 percent of all JavaScript shipped to the homepage is unused.** That's 624KB of bytes the user downloads, the browser parses, and the device's memory holds, for code that never runs. **For a typical mid-tier mobile device on slow 4G**, those 624KB cost roughly 3 seconds of total processing (download + parse + execute-skipped) over the page lifecycle.

2. **GTM at 142KB unused (rank 1) is the most addressable single item.** The GTM container ships every tag's setup code regardless of whether the tag fires on the current page. **Quarterly tag audit + page-scoped triggers** typically reduces GTM bundle size by 40-60 percent. Time investment: 3-5 hours of GTM workspace cleanup.

3. **Klaviyo SDK at 114KB unused (rank 2)** is partly structural (Klaviyo ships unified SDK with popup + behaviour + product feed components), partly addressable. **Lazy-loading the popup component** until the trigger fires saves 60-80KB; behaviour tracking still runs at page-load.

4. **Tidio chat at 110KB unused (rank 3)** can be deferred entirely to post-load. The chat widget doesn't need to load before first paint; users who don't engage with chat (90 percent of sessions) never need the JS at all.

5. **jQuery at 62KB unused (rank 4)** is structural to Stencil themes. Short-term: defer (covered in [`psi_render_blocking`](/nerve-centre/kpi-cards/website-performance/render-blocking-resources)). Long-term: write new theme code in vanilla JS or modern alternatives; eventually remove jQuery dependency entirely. **Multi-month project**, not a quick win.

6. **Stencil theme bundle at 54KB unused (rank 5)** is the cleanest code-split target. Modern bundlers can produce per-template chunks: homepage-only JS, PDP-only JS, collection-only JS. Each template loads only its own bundle plus shared core. **Code-splitting effort**: 2-4 weeks for a developer familiar with Webpack/esbuild + theme architecture; ongoing benefit compounds.

7. **Optimizely (rank 6)** ships the full A/B test variant fetcher even on pages without active tests. Configure to **lazy-load only when an active test targets the current page**. Saves 60-70KB on most pages.

8. **Cumulative impact estimation**: removing or deferring the top 7 entries cuts JS bytes by 400-500KB and parse time by 800-1,500ms. **Mobile p75 INP drops by 100-300ms**; mobile p75 LCP drops by 200-500ms (less direct, but JS competes with image rendering for main-thread time).

Diagnostic flow:

1. **Read top 5 entries.** Concentrate effort on the largest unused-byte items.
2. **Categorise per item**: third-party (defer or remove), first-party theme (code-split), framework (long-term replacement).
3. **Verify in DevTools Coverage tab**: confirms the unused-byte estimates and shows exactly which lines never ran.
4. **Ship in priority order**: third-party deferral first (fastest wins), then code-splitting (medium effort, large benefit), then library replacements (longest, structural).

Rapid-response playbook:

| Time horizon   | Action                                               |
| -------------- | ---------------------------------------------------- |
| First 1 hour   | Identify top 3 entries; verify Coverage in DevTools. |
| First 24 hours | Defer or remove dead third-party scripts.            |
| First 7 days   | GTM tag audit; lazy-load chat + popup.               |
| First 14 days  | Code-split first-party theme bundle.                 |
| First 30 days  | Re-audit; measure cumulative impact.                 |

## Sibling cards merchants should reference together

| Card                                                                                              | Why merchants reach for it                                                      |
| ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| [`psi_unused_css`](/nerve-centre/kpi-cards/website-performance/unused-css)                        | Same pattern for CSS; tree-shaking and code-splitting apply equivalently.       |
| [`psi_third_party_cost`](/nerve-centre/kpi-cards/website-performance/third-party-cost)            | Third-party scripts dominate unused-JS rankings on most ecommerce sites.        |
| [`psi_render_blocking`](/nerve-centre/kpi-cards/website-performance/render-blocking-resources)    | Render-blocking + unused-JS often overlap; deferring synchronous JS helps both. |
| [`psi_js_execution`](/nerve-centre/kpi-cards/website-performance/js-execution-time)               | Total JS execution time; correlates with unused JS plus active execution.       |
| [`psi_total_weight`](/nerve-centre/kpi-cards/website-performance/total-page-weight)               | JS bytes contribute to total weight.                                            |
| [`crux_inp_p75`](/nerve-centre/kpi-cards/website-performance/click-responsiveness)                | INP heavily affected by JS bundle size and parse time.                          |
| [`crux_lcp_p75`](/nerve-centre/kpi-cards/website-performance/page-load-speed)                     | LCP affected when JS competes with image rendering.                             |
| [`psi_top_opportunities_ms`](/nerve-centre/kpi-cards/website-performance/top-opportunities)       | Unused-JS typically ranks top 5 in opportunity list.                            |
| [`psi_perf_score_summary`](/nerve-centre/kpi-cards/website-performance/performance-score-summary) | Composite score; JS removal lifts TBT score (30 percent of weight).             |

## Reconciling against the vendor's own dashboard

**Where to look:**

* **[PageSpeed Insights](https://pagespeed.web.dev)**, "Reduce unused JavaScript" opportunity in the Diagnostics section.
* **Chrome DevTools → Coverage tab**, line-level visibility of which JS lines executed; the most useful diagnostic tool.
* **WebPack Bundle Analyzer** (or equivalent for esbuild/Vite), shows what's in your bundle and where the bytes go.

**Why the Vortex IQ unused-JS may differ from PSI / DevTools:**

| Reason                                                                                                                                                           | Direction                                           | What to do                                                              |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | ----------------------------------------------------------------------- |
| **Audit vs interaction.** Lighthouse measures unused JS during the synthetic page-load; pages with rich interactivity may execute more JS in real use.           | Vortex IQ may **over-report** for interactive pages | Use DevTools Coverage with manual interaction for a fairer measurement. |
| **Source maps not available.** Without source maps, Lighthouse reports unused bytes by raw bundle position; with source maps it can identify specific functions. | n/a (still measures correctly)                      | Source maps improve diagnostic clarity, not measurement accuracy.       |

**Cross-connector reconciliation:** mostly internal cross-references with [`psi_third_party_cost`](/nerve-centre/kpi-cards/website-performance/third-party-cost), [`crux_inp_p75`](/nerve-centre/kpi-cards/website-performance/click-responsiveness), and [`psi_total_weight`](/nerve-centre/kpi-cards/website-performance/total-page-weight).

**Quick rule for support tickets:** if a merchant says *"Lighthouse says I have 624KB of unused JS but my bundle is only 380KB total"*, the most common cause is that some bundles have grown over multiple deploys without proper invalidation; the merchant is looking at a single bundle while Lighthouse sees the cumulative bytes across all loaded scripts. Sum across all script tags in DevTools Network for direct comparison.

## Known limitations / merchant FAQs

**Why does my bundle have 60 percent unused JS?**

Modern frameworks and libraries are designed to ship many features; any single page typically uses a small subset. Plus: legacy code accumulates, polyfills target browsers you no longer care about, dead features get bundled even when not used. **The 60 percent figure is industry-typical**, not a sign of unusual mismanagement. Code-splitting and tree-shaking are the standard fixes.

**Will removing unused JS break my site?**

If done correctly, no. Modern bundlers track imports/exports and tree-shake automatically; the unused code never makes it into the bundle. **Manual code removal** (deleting dead files) requires more care; verify with your test suite plus a 14-day staged deploy.

**Can I just defer all my JS?**

Technically yes, but conversion-critical scripts must run for the page to function. **Deferring is for non-critical**: chat widgets, session recording, A/B testing, analytics tags. **Don't defer**: payment SDKs (must be ready when checkout fires), authentication scripts, scripts that handle initial-render content.

**Why does Klaviyo SDK show as 64 percent unused?**

Klaviyo ships a unified SDK with popup + behaviour tracking + product feeds + signup forms + opt-in management. Most pages use only behaviour tracking; the rest is dead weight per page-load. **Lazy-loading the popup component** is Klaviyo's recommended optimisation; the SDK is configurable.

**Should I switch from jQuery to vanilla JS?**

Long-term, yes. Modern browsers support all jQuery's core features natively (`querySelector`, `fetch`, `addEventListener`); jQuery added value 10 years ago when browser inconsistencies were common. **Migration is gradual**: write new code in vanilla JS, leave existing jQuery code in place, retire jQuery when the codebase is mostly migrated. **Saves 84KB** of bundle size when complete.

**Can Vortex IQ refactor my JS for me?**

Read-only by design. Vortex IQ identifies unused JS; the merchant's developer or agency does the bundle work.

**My BC site uses Catalyst. Does this still apply?**

Yes, in different proportions. Catalyst sites use Next.js with built-in code-splitting; first-party JS unused bytes are typically 10-20 percent (vs 30-40 percent for Stencil). Third-party JS unused proportions are similar. **The optimisation effort shifts**: Catalyst sites focus on third-party deferral; Stencil sites focus on first-party code-splitting plus third-party deferral.

**Is server-side rendering the answer?**

Helps but isn't a complete fix. SSR delivers fully-rendered HTML to the user, removing the need for JS to render initial content. Unused JS still ships and parses; it just doesn't block the first paint. **SSR's main benefit** is LCP improvement; unused-JS reduction requires the same code-splitting work on top.

**Should I optimise unused JS or unused CSS first?**

JS first, almost always. JS has higher bytes-per-page on most ecommerce sites (200-1000KB vs 50-200KB for CSS), and JS execution cost is more variable across devices than CSS. Unused JS impacts INP heavily; unused CSS mainly affects parse time which is smaller.

***

### Tracked live in Vortex IQ Nerve Centre

*Unused JavaScript* is one of hundreds of KPI pulses Vortex IQ tracks across Website Performance (PageSpeed + CrUX) and 70+ other ecommerce connectors. Nerve Centre runs the detection layer; Vortex Mind investigates the cause when something moves; Ask Viq lets you interrogate any number in plain English.

[Start for free](https://app.vortexiq.ai/login) or [book a demo](https://www.vortexiq.ai/contact-us) to see this metric running on your own data.
