Skip to main content
Card class: Non-HeroCategory: Website Performance

At a glance

Total JavaScript execution time on the main thread, in milliseconds, not bytes downloaded but wall-clock CPU time spent parsing, compiling, and evaluating JS. High execution time is the single biggest cause of bad INP scores on mobile: when the main thread is busy, every tap, scroll, and click waits for JS to yield. Cutting JS execution time is one of the highest-leverage performance fixes for ecommerce because it directly improves interactivity, which directly affects bounce rate and conversion. A page can have moderate weight but high execution time if the JS is parse-heavy or runs expensive synchronous work on load.
What it countsCumulative milliseconds of main-thread work attributed to JavaScript execution during the audit (parse + compile + evaluate + execute), as measured by Lighthouse’s bootup-time audit. Excludes idle time and non-JS main-thread work.
Sample typeLab data from per-page Lighthouse audit; emulated 4× CPU throttle + slow 4G network.
Why JS execution time mattersMobile devices run typical site JS 4-6× slower than the desktop machines on which the JS was written. A 400ms JS execution on the developer’s MacBook is 1.6-2.4 seconds on a typical mobile shopper’s phone. This time is the dominant contributor to TBT (Total Blocking Time) and INP (Interaction to Next Paint), the two CWV metrics where ecommerce stores most often fail.
Reading the value(1) Compare against thresholds: under 1,000ms is healthy, 1,000-2,500ms needs attention, above 2,500ms is critical. (2) Decompose by script source via the Lighthouse audit row, first-party theme JS, jQuery, vendor bundles, third-party widgets each show their contribution. (3) Cross-reference psi_unused_js to see which bytes are dead weight that could be removed entirely. (4) Cross-reference psi_third_party_cost to see how much execution belongs to third parties.
Currencymilliseconds.
Time windowT/7D (per-audit).
Alert triggerjs_execution > 2500ms (severe main-thread blockage; INP and TBT will fail).
Sentiment keylower-is-better.
Rolesowner, 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, mobile homepage audit, Wednesday 15 May 26.
Script sourceJS bytes (KB)Parse + compile (ms)Evaluate + execute (ms)Total exec (ms)Share of total
Theme bundle (first-party)48028054082028%
jQuery 3.x8840601003%
GTM container182060803%
Yotpo reviews widget22018038056019%
Klaviyo onsite SDK1109022031011%
Hotjar heatmap60401401806%
Meta pixel + helpers40301101405%
Recombee recommendations70501301806%
Shopify Checkout SDK polyfills908020028010%
Other (theme widgets, A/B test)75602002609%
Total1,2518702,0402,910100%
What the JS execution analysis is telling us:
  1. Total JS execution at 2,910ms is in the critical zone. Above 2,500ms threshold; INP and TBT will fail by definition. The main thread is blocked for the better part of three seconds during page load, which is why every interaction during that window feels sluggish.
  2. Theme bundle is the single largest contributor (820ms, 28%). This is first-party code, fully within the merchant’s control to fix. Likely causes: jQuery dependency (88KB on its own), unminified or unsplit bundle, expensive synchronous initialisation, hero carousel and modal frameworks loaded eagerly. Code-splitting + tree-shaking + jQuery removal could realistically cut this to 250-350ms.
  3. Yotpo reviews widget at 560ms (19%) is a major third-party tax. Reviews are a critical conversion driver but reviews don’t need to render for first paint. Defer Yotpo until user scrolls below the fold or until idle. Cuts 400+ms off the critical path while preserving the feature.
  4. Klaviyo onsite SDK at 310ms (11%). Powers popup/embed forms, live shopping widgets, abandonment tracking. Defer initialisation, Klaviyo’s modern SDK supports lazy initialisation. Saves 200ms on critical path.
  5. Shopify Checkout SDK polyfills at 280ms (10%). Loaded site-wide for a homepage that doesn’t show checkout, wasted on every non-checkout pageview. Conditionally load on checkout-adjacent pages only. Saves 280ms on homepage and other non-checkout templates.
  6. Hotjar, Meta pixel, Recombee combine for ~500ms. Tracking and recommendations infrastructure. Server-side tagging (Meta CAPI, server-side recommendation injection) shifts this off the browser entirely. Saves 400ms on critical path.
  7. Recommended ship sequence:
    • Week 1: Defer Yotpo + Klaviyo until idle/scroll. Saves ~600ms.
    • Week 2: Conditional load Checkout SDK polyfills. Saves ~280ms.
    • Week 3: jQuery removal + theme bundle code-split. Saves ~500ms.
    • Week 4: Server-side tagging migration for Meta/Hotjar. Saves ~400ms.
    • Result after 4 weeks: 2,910ms → 1,100-1,300ms. INP and TBT move from failing to passing. Mobile interactivity feels noticeably faster.
  8. Why this card matters for INP specifically. INP measures the time between a user interaction (tap, click) and the next visual frame. Long JS execution starves the main thread, so even a brief tap during page load waits hundreds of milliseconds for JS to yield. Cutting JS execution time directly improves INP and field CWV pass rate.
The diagnostic flow:
  1. Read total JS execution time. Anything above 1,500ms warrants action.
  2. Decompose by script source. Identify the top 3 contributors.
  3. Apply pattern-based remediation: defer (third parties), conditional load (per-route polyfills), code-split (first-party bundle), server-side (tracking).
  4. Re-audit to confirm execution drops below 1,500ms.
Rapid-response playbook:
Time horizonAction
First 1 hourIdentify top 3 script-source contributors.
First weekDefer non-critical third parties.
Day 14Code-split first-party bundle.
Re-auditConfirm execution under 1,500ms. INP/TBT pass.

Sibling cards merchants should reference together

CardWhy merchants reach for it
psi_unused_jsJS bytes shipped but never executed; remove to cut both bytes and execution time.
psi_lab_tbtTotal Blocking Time; direct downstream of JS execution time.
crux_inp_p75Field INP; high JS execution causes high INP.
psi_third_party_costThird-party tax; identifies which third parties are most expensive.
psi_render_blockingRender-blocking resources; subset of JS execution.
psi_total_weightTotal page weight; complements but distinct from execution.

Reconciling against the vendor’s own dashboard

Where to look:
  • PageSpeed Insights → “Reduce JavaScript execution time” diagnostic, lists each script with its execution time on a 4× CPU-throttled emulated mobile device.
  • Chrome DevTools → Performance panel, record a page load, look at the “Bottom-Up” tab grouped by script source for actual main-thread time.
  • Lighthouse audit JSON → bootup-time audit, array of script URLs with total, scripting, and scriptParseCompile fields.
Why the Vortex IQ value may differ from manual checks:
ReasonDirectionWhat to do
Device CPU. Lighthouse uses a 4× throttle to emulate slow mobile. A manual run on a fast desktop (no throttle) shows much lower numbers.Vortex IQ higherApply CPU throttling in DevTools when reconciling.
Network throttle. Lighthouse uses Slow 4G; this affects script download timing which can shift execution timing.VariableMatch throttle profile when reconciling.
Run-to-run variance. Lighthouse JS execution ±15% is normal due to V8 optimisation phases.Either directionUse 7-day rolling.
Browser version. V8 changes between Chrome releases can shift JS execution by ±10-15%.Either directionNote the Chrome version used.
Cross-connector reconciliation: primarily internal (with psi_unused_js, psi_lab_tbt, psi_third_party_cost). Quick rule for support tickets: when a merchant disputes the JS execution number, run their PageSpeed Insights URL and compare directly. The Vortex IQ value should match the PSI “Reduce JavaScript execution time” diagnostic within ±15% on the same audit cycle.

Known limitations / merchant FAQs

Q: Our JS execution time is 2,800ms in Lighthouse but our real users say the site feels fine. Should we worry? Probably yes, but check field data first. Lighthouse simulates a slow mid-tier mobile device. If your audience is mostly desktop or premium iPhone, your real users may not feel the pain. Look at crux_inp_p75 field data, if INP is below 200ms in field, you’re fine; if INP is above 200ms, real users are feeling the JS execution cost. Q: We deferred all third parties and execution time only dropped 600ms. Why not more? Because much of the JS execution is first-party theme code that runs on every page regardless of third parties. Inspect the per-script breakdown, if theme bundle is 800ms+, that’s the next target. Code-splitting the theme bundle and removing jQuery typically cuts another 300-500ms. Q: Removing jQuery sounds risky. Is it worth it? Almost always yes for ecommerce. jQuery adds 88KB and 80-150ms execution time on mobile. Modern themes (Catalyst, Stencil 2.0) ship without jQuery. Most jQuery uses (DOM selection, AJAX, animations) have native equivalents (querySelector, fetch, CSS animations). The migration takes 1-2 sprints of focused work but pays back permanently in execution time. Q: GTM container shows only 80ms execution time. Why is server-side tagging worth the investment if GTM is so cheap? Because the GTM container itself is cheap, but the tags it loads aren’t. A typical GTM container fires 30+ tags, each running its own JS, Meta pixel, Google Ads pixel, Hotjar, conversion tracking, abandonment tracking. The 80ms is just the dispatcher; the dispatched tags often add 600-1,000ms of cumulative execution. Server-side GTM moves the tag execution off the browser entirely. Q: Our Yotpo widget execution is 560ms. Yotpo is essential for conversion. What can we do? Defer initialisation. Yotpo (and most review widgets) support lazy-loading, they don’t need to render until the user scrolls to the reviews section. Setting data-deferred="true" or wrapping in an IntersectionObserver pattern keeps the feature but moves the execution off the critical path. This is a configuration change, not a feature removal. Q: We code-split our bundle but execution time barely moved. Why? Code-splitting reduces the bytes downloaded on initial page load, but if the split chunks still fire synchronously on load (rather than on-demand), execution time stays the same. The fix is dynamic import() triggered by user action or visibility, not just splitting the file. Verify in DevTools that the split chunks are actually loading lazily. Q: How does this card differ from psi_total_weight and psi_unused_js? psi_total_weight measures bytes downloaded. psi_unused_js measures bytes downloaded but unused. This card measures CPU time spent executing the bytes. All three are needed: bytes affect download time, unused bytes are pure waste, and execution time affects interactivity. A page can be light on bytes but heavy on execution if the JS is parse-intensive (e.g., minified but not tree-shaken). Q: We reduced JS execution by 1,000ms and our Lighthouse score barely moved. Why? Lighthouse Performance Score weights LCP (25%), TBT (30%), CLS (25%), FCP (10%), Speed Index (10%). JS execution improvements feed into TBT primarily. If your TBT was already passing, further reductions show diminishing score returns even though field INP improvement may be substantial. Track field INP (crux_inp_p75) for the real-world payoff.

Tracked live in Vortex IQ Nerve Centre

JS Execution Time 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 or book a demo to see this metric running on your own data.