The checkout page is the single most expensive place for a WooCommerce store to be slow. A homepage that takes 4 seconds gets a bounce. A checkout that takes 4 seconds gets an abandoned cart and a charged Stripe attempt that never closes. Baymard's research puts checkout abandonment at 70% across e-commerce; performance is consistently the top-3 reason cited.
This is the audit walk we use on every store BoltAudit reviews. It is structured around the four layers of a WordPress site, in the order they tend to be at fault on checkout specifically.
Why checkout is slow in a way no other page is
The checkout page is unique in the WordPress universe for three reasons that make it harder to optimize than any other URL on your site:
- It cannot be page-cached. Checkout pages contain user-specific cart contents, shipping totals, and form state. Page caching plugins skip them by design. So every checkout view hits the origin uncached, hammering whatever your real backend speed is.
- It runs every payment, shipping, and tax plugin synchronously. Checkout fires
woocommerce_checkout_init, which in turn runs every gateway'sis_availablehook, every shipping method's rate calculator, and every tax provider's lookup — often as live API calls — before the page renders. - It is rendered by the theme like any other page. That means all the same render-blocking JS, oversized hero images, and heavy fonts your homepage has — except now they sit on top of an already-slow uncached request.
The result is the worst of every layer at the same time. A 200ms regression on the homepage is barely noticed; a 200ms regression on checkout is a real conversion drop.
Layer 1: Backend (the big one)
For 70% of WooCommerce stores we audit, the checkout bottleneck lives in the backend. That means PHP, hooks, plugins, and external API calls. Three culprits dominate:
Payment gateways doing live is_available checks
Every payment gateway you have installed runs WC_Payment_Gateway::is_available() on every checkout load. Most reasonable gateways check a setting and return. Some — particularly fraud detection plugins, BNPL providers, and license-checked plugins — make a live API call. Three plugins each adding 200ms means a 600ms checkout penalty on every load.
Fix: deactivate any gateway you are not actively using. For ones you keep, check the plugin settings for "verify license on each request" or "live availability check" and turn them off.
Shipping methods recalculating rates from scratch
The shipping zone matching is fast. The actual rate calculation can be brutal — especially if you are using ShipStation, EasyPost, or a courier-specific live-rates plugin. Each plugin makes a live API call to fetch rates per cart, and they often do not cache the result.
Fix: enable WooCommerce's built-in shipping cache (woocommerce_shipping_method_count_transient) and consider switching to flat rates with a fallback to live rates only for international zones. We have seen this single change drop checkout TTFB by 800ms.
Tax providers (Avalara, TaxJar, etc.)
Same pattern — synchronous external API call on every cart change. The fix is either a longer cache on the tax response, or moving tax calculation to the post-order step instead of the live cart step.
A diagnostic shortcut: deactivate every WooCommerce extension that is not core (payments, shipping, tax) and reload checkout. If TTFB drops by more than 300ms, the extension load is your problem and you reactivate them one at a time to find the one responsible.
Layer 2: Database
WooCommerce checkout hits the database harder than any other page. The fast checks:
Autoload bloat
Every page load reads wp_options rows where autoload='yes'. Stores that have run for two or more years tend to have 1–6MB of autoloaded data, much of it stale settings from deactivated plugins. Run:
SELECT SUM(LENGTH(option_value)) / 1024 AS autoload_kb
FROM wp_options WHERE autoload = 'yes';
If that returns over 1024 (1MB), you have a real problem. If over 3MB, you have a 200ms TTFB penalty on every uncached page including checkout.
Session table contention
Stores with high traffic see heavy contention on wp_woocommerce_sessions. The default cleanup is once a day; on a busy store that table can grow to hundreds of thousands of rows mid-day, slowing every cart and checkout query.
Fix: cron a more aggressive cleanup, or move sessions to Redis with the WP Session Manager plugin.
Postmeta orders fanning out
Order metadata lives in wp_postmeta (or, if you have migrated, wp_wc_orders_meta). Plugins that read order meta on the cart/checkout page often do N+1 lookups. The fix is the High Performance Order Storage (HPOS) migration if you haven't already done it; it gives you indexed columns instead of generic postmeta lookups.
Layer 3: Frontend
Frontend is usually a smaller win than the backend on checkout, but it is often the most visible to users. The three checks:
Render-blocking checkout scripts
WooCommerce ships several scripts that block render on checkout: wc-checkout, wc-country-select, wc-address-i18n, plus whatever payment gateway scripts your gateways enqueue. Stripe, for example, loads stripe.js synchronously by default. Defer or async every script that does not need to run before paint, and load gateway scripts only on the gateway's actual checkout panel.
Heavy fonts on a non-decorative page
Many themes load 4–6 font weights from Google Fonts (or self-hosted) on every page. Checkout needs at most regular and bold. Subset, self-host, and font-display: swap.
Address autocomplete plugins
Google Places autocomplete and other address-completion plugins each load a 60–200KB JS bundle. They are useful, but you only need one. If you have multiple, pick one and deactivate the rest.
Layer 4: Infrastructure
The smallest lever, but worth checking once you have done the other three. If you are still on shared hosting after fixing layers 1–3, you have probably hit the ceiling of what shared hosting can do for a checkout page.
The signals that infra is the actual bottleneck:
- Uncached TTFB is over 800ms even after disabling all non-core extensions.
- Adding PHP workers does not help.
- The host's CPU is pinned during normal traffic.
- Object caching (Redis) is unavailable on your plan.
If three of those four are true, switching to a host with managed Redis and PHP-FPM tuned for WordPress (Pressable, Kinsta, Cloudways' Vultr High-Frequency, etc.) will give you a real win. But, again — do layers 1–3 first. Most stores get a faster checkout by removing one shipping plugin than by changing hosts.
The order of operations
If you are going to fix one thing this week:
- Run an uncached TTFB measurement on
/checkout(curl with a cache-bust query string). - Deactivate every non-core WooCommerce extension and remeasure. If the delta is over 300ms, you have a backend extension problem — reactivate one at a time to find the culprit.
- Run the autoload size check above. If it is over 1MB, clean it.
- Do the frontend audit only after the first two are done.
If you are going to fix one thing this month: migrate to HPOS, audit your shipping/tax plugins, and put session storage on Redis. That stack will hold a slow-but-stable checkout under a Black Friday load.
What BoltAudit does
BoltAudit runs the four-layer walk above in 90 seconds against your live site. Instead of "your checkout is slow" you get "this shipping plugin is adding 480ms per checkout, your autoload is at 2.1MB, and stripe.js is render-blocking — fix in this order for a projected 1.4s win." That is the audit a senior performance engineer would write up — produced automatically.
Run a free audit on your store. The first audit is free; if the bottleneck verdict surprises you, you found a fix worth shipping.
Run BoltAudit on your site
Free plugin · 1 site · 3 audits per month · no credit card.