Performance
Reduce JavaScript on checkout pages
Reduce JavaScript checkout is the job of cutting every script that is not payment, validation, address, shipping or the conversion tag you still trust, so the customer can finish an order without waiting on chat, reviews, heatmaps and merchandising widgets. Checkout is not a homepage. It should not load like one.
I am Alan Vo, Gold Coast web developer, 18 years on Magento, Shopify and WooCommerce. The fastest conversion win I still see is not a new theme. It is deleting tags from cart and checkout. web.dev’s unused JavaScript guidance is the general practice. This note is the store-shaped version: begin_checkout to purchase.
Why you reduce JavaScript checkout before you rewrite the theme
You reduce JavaScript checkout because INP on fields and buttons is where orders die, and because most of the JS on those URLs was bought for browsing, not for paying. Reviews stars do not belong next to a credit card field. A storewide chatbot that opens on cart is competing with the place-order button.
Shopify, Woo and Magento all accumulate the same junk: GTM All Pages tags, loyalty points widgets, product recommendations that still call a recommendation API on a page with no products, session replay, Facebook pixels that were meant for PDP, and page-builder remnants if checkout is still “in theme.”
WooCommerce is famous for it (fragments, jQuery, extra plugins). Read WooCommerce checkout INP for the platform-specific version. The rule is identical on Shopify checkout extensibility and Magento checkout: allowlist, do not denylist after the fact.
Their Nibs is a Shopify rebuild I shipped as contract work on an agency team. Published results after launch: 31% conversion lift, 48% more orders. The purchase path had to stay first. That includes not hanging checkout on storefront apps. Janet and Janet is WooCommerce footwear with campaign photography. The PDP can be heavy. Checkout must not inherit that weight.
What “reduce JavaScript checkout” means in the bundle
Reduce JavaScript checkout means you measure the JS on cart, checkout and thank-you separately from PLP/PDP, then you remove or defer everything that is not in the allowlist.
My default allowlist:
- Platform checkout runtime (Shopify Checkout, Woo blocks or classic, Magento checkout JS you actually need).
- Payment and wallets (after user intent if the vendor allows, never broken).
- Address autocomplete if it is the chosen UX, one library not three.
- Consent and the purchase/conversion tags that legal and media agreed on.
- Fraud tools the gateway requires.
My default denylist on those URLs:
- Chat, reviews, UGC, loyalty popups, Klaviyo/onsite forms that already captured the email in cart.
- Heatmaps and session replay.
- Recommendation carousels.
- A/B tools still running a homepage experiment.
- Duplicate analytics (GTM plus native plus app).
- Social share and design-system leftovers.
Deferral of marketing tags is a sister technique: load GTM after interaction on browse pages, keep purchase honest. See defer third-party tags without losing data. On checkout I am harsher. I often do not load marketing GTM at all until thank-you, and I fire purchase from a dedicated path (pixel, dataLayer on success, or server). That is a design choice you document so media does not think you “turned off tracking.”
Unused JavaScript in Lighthouse on checkout is a hint. The real unused is a 200KB file that never runs a function the checkout needs. Tree-shaking your theme is good. Removing an app is better.
How I strip checkout JS on each platform
Shopify: theme app embeds have URL settings. Turn them off on /checkout if they still inject via the storefront while the customer is in checkout. Checkout UI extensions should be counted. If an extension is a banner, ask whether it converts. Web pixels should be purchase and consent, not a second GTM. Storefront GTM should not be copied into checkout.liquid era hacks. You should already be on extensibility.
WooCommerce: disable plugins by page with a must-use plugin or the plugin’s own “disable on checkout” setting. Cart fragments polling is an INP tax. Block checkout versus shortcode changes the JS graph. Do not add Elementor to checkout to “style the button.” Payment plugins stay. Marketing plugins go.
Magento: disable modules on checkout via layout XML handles (checkout_index_index, onepage). Bundling is not a strategy if the bundle still contains reviews. Hyva or not, checkout modules are the audit.
GTM: create a trigger exception for Chat, Hotjar, reviews, and anything with a timeout, on Page Path contains checkout, cart, order-received, thank-you. Do not use All Pages for those tags. Container optimisation (less gtag.js) is extra; it does not replace this.
Payments: never “async defer” a wallet in a way that hides Apple Pay until after a long timeout. Customers think you do not support it. Load wallets according to the vendor’s checkout docs.
Thank-you pages pick up the same junk because they share the theme footer. A reviews popup on order confirmation is not a conversion. It is a main-thread tax after the customer already paid, and it can steal the click on “print receipt” or “create account.” Keep thank-you to order summary, account prompt if you use it, and the purchase tag. Loyalty points can wait for the next session.
I also watch web fonts on checkout. A second font family that only exists to match the brand homepage is not worth a late text paint on a postcode field. System UI on checkout is allowed. Brand can come back on the success page if legal is happy.
When a media manager says “we need the same GTM on checkout as the rest of the site so attribution works,” I show them begin_checkout and purchase as events, not as a reason to load chat. Attribution needs those two events and a clean landing page. It does not need Hotjar on the CVV field.
Production checklist to reduce JavaScript checkout
- Save a WebPageTest or DevTools coverage run on checkout as the baseline. Note JS kilobytes and long tasks while typing in the email field.
- List every script URL. Mark allow or deny.
- Remove denylist apps/plugins from checkout in staging.
- Add GTM exceptions. Publish a workspace that only changes triggers.
- Confirm wallets, shipping calculators, discount fields, and validation still work on mobile.
- Place test orders on card, wallet, and a failing card. Purchase tag still fires once on success only.
- Measure INP-style interaction: focus field, open shipping method, apply coupon. Long tasks should drop.
- Watch begin_checkout to purchase in GA4 for a week. If purchase drops, you over-cut a tag, not “the page got faster.”
- Repeat after every app install. New apps default to All Pages.
- Put the allowlist in the repo or the GTM notes so the next campaign does not restore chat on checkout “for recovery.”
What breaks when you reduce JavaScript checkout badly
You defer the payment SDK. Place order does nothing. That is not a vitals win.
You strip GTM entirely and forget a web pixel. Media has no purchase. They scale spend down.
You exclude cart but not mini-cart drawers on the theme, so ATC still pulls the whole marketing stack while checkout itself is clean. Customers still feel slowness on the path in.
You remove fraud JS the gateway needs. Chargebacks later. Confirm with the PSP.
You rely on a CSS display:none of a chat widget. The JS still runs. INP does not care that the bubble is invisible.
You minify and combine everything in a WordPress plugin that breaks wallet iframes. Combining is not reducing.
You test only as a logged-in admin with cache bypass. Real customers still download the chat script.
On Janet and Janet, campaign photography is the PDP story. If that gallery JS leaks into cart through a global enqueue, you did not reduce JavaScript checkout. You reduced a lab URL.
How I measure a checkout JS cut
Bytes of JS on checkout, before/after, mobile cable.
Longest task while typing, before/after.
INP in RUM for checkout URLs if you have it. If not, a lab interaction trace plus field conversion.
Funnel: begin_checkout, add_shipping_info, add_payment_info, purchase. The count of purchase over begin_checkout should not collapse. If it improves, you may have removed a blocker. If it collapses, restore tags one at a time.
Gateway orders versus GA4 purchase, so you know whether you broke measurement.
Their Nibs’ published conversion and order lifts were about the whole journey. Checkout JS is one slice of that journey. I still isolate it when I debug.
Related work on this site
Their Nibs is Shopify with a documented conversion and order movement after a rebuild that put purchasing first. Janet and Janet is WooCommerce shoes where imagery is heavy and checkout must stay a shop. Those two are why I will not load a reviews pixel on a card field.
For Woo-specific interaction cost, read WooCommerce checkout INP. For the marketing tags that sneak back via GTM, read defer third-party tags without losing data.
FAQ
What does reduce JavaScript checkout mean if we use Shopify hosted checkout?
Reduce JavaScript checkout still means storefront cart and any checkout extensions, pixels and apps that run on the way into checkout. Hosted checkout has its own constraints. You still turn off storefront junk on cart, and you still keep pixels to a purchase allowlist.
Will reduce JavaScript checkout hurt remarketing?
It can reduce browse tags on checkout URLs, which is what you want. Remarketing should run on catalogue pages. Purchase should run on success. If your only Facebook event was on checkout, you had a brittle setup. Move it to a documented purchase event.
Is unused JavaScript the same as reduce JavaScript checkout?
Unused JavaScript is Lighthouse’s coverage of functions not called on that load. Reduce JavaScript checkout is deleting whole products from that load. Do both. Deleting chat beats tree-shaking chat.
Where is the official guidance to reduce JavaScript checkout?
Google’s unused JavaScript article on web.dev is the general technique. Platform checkout docs (Shopify, Woo, Magento) tell you what you must keep. This post is the allowlist I actually use on stores.
Keep reading
Contact if you want this kind of work on a live store.