When a store owner asks us to fix WooCommerce checkout page slow loading, the first thing we do is nothing. No caching plugin, no CDN toggle, no “optimize database” button. Checkout is the one page in WooCommerce that page caching cannot help, because it is generated fresh for every visitor with their specific cart, address and payment options. Guessing at fixes here wastes days. Measuring takes about an hour.
This article is for anyone responsible for a WooCommerce store where the checkout takes three, five or ten seconds to load, or to update when the customer changes their address. It walks through the diagnosis we run in every checkout performance engagement, the causes we find most often, and the fixes in the order of how much they typically help.
why checkout is different from every other page
A product page can be served from a full-page cache in under 100 ms. Checkout cannot, and WooCommerce enforces this: it defines the DONOTCACHEPAGE constant and sends no-cache headers on cart, checkout and account pages. Every request therefore runs the whole stack: WordPress boot, every active plugin, a session lookup in wp_woocommerce_sessions, cart totals, shipping calculation, tax calculation, gateway initialisation and template rendering.
It also happens more than once. After the page loads, the checkout JavaScript fires an update_order_review AJAX request (?wc-ajax=update_order_review) whenever the address, shipping method or coupon changes. That request recalculates shipping and taxes from scratch. So a slow checkout is really two problems: initial page generation and the cost of each recalculation. Both need measuring separately.
diagnose first: three tools that find the cause in an hour
Query Monitor for the server side
Install Query Monitor on a staging copy, log in as an administrator, and load the checkout page with items in the cart. The panels that matter are Queries by Component (which plugin is consuming the most database time), HTTP API Calls (any outbound request during page load is a red flag) and Hooks & Actions for anything expensive on woocommerce_checkout_init or template_redirect. Then change the shipping address and look at the AJAX request in Query Monitor’s log. If you see the same outbound HTTP call on both, you have already found the likely cause.
WP-CLI profiling for exact numbers
Query Monitor shows you what runs; wp profile shows how long each stage and hook takes without a browser in the way:
wp package install wp-cli/profile-command
wp profile stage --url=https://example.com/checkout/ --fields=stage,time,query_time,query_count
wp profile hook --all --url=https://example.com/checkout/ --orderby=time --order=desc --fields=hook,callback_count,time | head -20
wp profile hook woocommerce_checkout_init --url=https://example.com/checkout/
Run each command three times and take the median. Anything above one second in a single hook is where you start.
browser DevTools for the front end
Open the Network tab, disable cache, and reload checkout. Note three numbers: time to first byte of the HTML document, the total count of script and style files, and the duration of the update_order_review request after changing a field. A healthy store on decent hosting is typically under 600 ms TTFB and under 400 ms for the AJAX call. If TTFB is fine but the page feels slow, the problem is script weight, not PHP.
the server-side causes we find most often
live shipping and tax API calls on every recalculation
The single most common cause. A carrier rate plugin (UPS, FedEx, DHL, Australia Post) or a tax service (TaxJar, Avalara) calls an external API every time the address changes. WooCommerce caches calculated shipping rates in a transient keyed on a hash of the package contents and destination, but many plugins add changing data to the package (timestamps, session ids) that breaks the hash and forces a fresh API call every time. Query Monitor’s HTTP API Calls panel shows this immediately.
bloated wp_options autoload
Every request loads every autoloaded option into memory. On stores we take over, the autoload set is often 5 to 20 MB because of expired transients, plugin logs and abandoned settings. That cost applies to checkout and to every AJAX call.
wp option list --autoload=on --fields=option_name,size_bytes --format=csv | sort -t, -k2 -n -r | head -25
wp transient delete --expired
wp db query "SELECT ROUND(SUM(LENGTH(option_value))/1024/1024,2) AS autoload_mb FROM wp_options WHERE autoload='yes'"
session table and Action Scheduler backlog
wp_woocommerce_sessions grows with every guest visitor. WooCommerce cleans it via the woocommerce_cleanup_sessions scheduled action, but if WP-Cron is broken or Action Scheduler has a backlog of tens of thousands of pending rows in wp_actionscheduler_actions, the table balloons and every session lookup slows down. Check WooCommerce > Status > Scheduled Actions for anything past due, and make sure a real system cron runs wp cron event run --due-now every minute instead of relying on visitor-triggered WP-Cron.
too many payment gateways initialised
Each active gateway runs its constructor when WooCommerce loads gateways, and some (particularly ones that verify credentials or fetch configuration remotely) do slow work there. Stores with six gateways enabled “just in case” pay for all six on every checkout load and every recalculation.
slow database from meta bloat
Cart and order calculations touch wp_postmeta heavily unless High-Performance Order Storage is enabled. A wp_postmeta table with 30 million rows makes every product lookup slower. Our database cleanup checklist covers the fix; the short version is enable HPOS, regenerate the product lookup tables and remove orphaned meta.
the front-end causes
Themes and plugins enqueue scripts globally without checking the page. We regularly see sliders, map libraries, social sharing, page builder frameworks and three different jQuery UI bundles loaded on checkout where none of them are used. Each one delays the checkout script and adds a chance of a JavaScript error that breaks the update_order_review call entirely. Payment gateways add their own weight: Stripe, PayPal and Klarna each load their SDKs, which is necessary, but they should load only when that gateway is actually available to the customer.
To see exactly what is loading, Query Monitor’s Scripts and Styles panels list every enqueued handle with the plugin or theme that registered it. Export that list on checkout and on a product page and compare. Anything present on checkout that a customer entering an address cannot possibly need is a candidate for removal. In a recent engagement that list was over 90 handles on checkout, of which fewer than 20 were used, and the page became interactive roughly two seconds sooner once the rest were dequeued.
how to fix WooCommerce checkout page slow loading, in order of impact
1. cache or throttle external rate lookups
If a shipping or tax plugin makes live calls, first check its own settings for a caching option; most have one and it is often off. If it does not, wrap the lookup in a transient keyed on destination postcode, country and cart weight, with a lifetime of a few hours. Rates do not change minute to minute. For tax, TaxJar and Avalara both support calculating at order placement rather than on every recalculation, which cuts the calls from several per session to one.
2. remove scripts and styles that do not belong on checkout
add_action( 'wp_enqueue_scripts', function () {
if ( ! function_exists( 'is_checkout' ) || ! is_checkout() ) {
return;
}
$remove = [ 'slick', 'swiper', 'elementor-frontend', 'wc-add-to-cart', 'jquery-ui-datepicker', 'font-awesome' ];
foreach ( $remove as $handle ) {
wp_dequeue_script( $handle );
wp_dequeue_style( $handle );
}
// Cart fragments serve the mini-cart; checkout does not need them.
wp_dequeue_script( 'wc-cart-fragments' );
}, 100 );
Test with every gateway after doing this. Dequeue the wrong handle and a gateway silently fails to render its card field.
3. limit gateways to the ones that can actually be used
add_filter( 'woocommerce_available_payment_gateways', function ( $gateways ) {
if ( is_admin() || ! function_exists( 'is_checkout' ) || ! is_checkout() ) {
return $gateways;
}
$country = WC()->customer ? WC()->customer->get_billing_country() : '';
if ( 'US' !== $country ) {
unset( $gateways['affirm'], $gateways['klarna_payments'] );
}
if ( WC()->cart && (float) WC()->cart->get_total( 'edit' ) < 50 ) {
unset( $gateways['bacs'] );
}
return $gateways;
} );
4. move sessions and object cache to Redis
With a persistent object cache, WooCommerce session reads and the thousands of get_option and get_post_meta calls per checkout come from memory. Install the Redis Object Cache plugin, confirm with wp redis status, and watch Query Monitor’s query count on checkout drop, often from several hundred to well under a hundred.
5. trim the checkout itself
Fewer fields means fewer validations and less JavaScript. Remove fields you do not use with the woocommerce_checkout_fields filter, and consider whether address autocomplete is worth the extra third party script. If you are still on the classic shortcode checkout, the block-based checkout in recent WooCommerce versions recalculates through the Store API (/wc/store/v1/cart) and is generally faster at updates, but it needs every gateway and plugin to support blocks first.
6. fix the server
PHP 8.2 or later with OPcache enabled, enough PHP-FPM workers that requests do not queue, and MySQL with an InnoDB buffer pool that fits your working set. On shared hosting you often cannot change any of these, which is one of the reasons stores move to a VPS or AWS once checkout speed becomes a revenue problem. If the page is fast on the server but slow to become interactive, the remaining work overlaps with our Core Web Vitals guide, particularly the INP section.
measure again, then keep it that way
Re-run the same three measurements after each change, not after all of them. You want to know which change did what, because the next plugin update may undo one of them. Once you fix WooCommerce checkout page slow loading, keep it fixed: put a synthetic checkout check into your monitoring, a script that adds a product to the cart, loads checkout and records TTFB and the update_order_review duration daily. Regressions then show up as a trend rather than as a support ticket. This is part of what an ongoing maintenance and support plan covers for the stores we look after, alongside the Core Web Vitals work that keeps the rest of the site fast.
when to do this yourself vs hire someone
Do it yourself if Query Monitor points clearly at one plugin, your hosting lets you change PHP settings, and you have a staging site to test on. Most single-cause slow checkouts are a settings change or a plugin swap.
Hire someone when the profile shows several causes contributing a few hundred milliseconds each, when the store has custom checkout code nobody remembers writing, when a shipping or tax plugin cannot be replaced and needs a caching layer written around it, or when checkout speed is directly costing sales and you need it fixed this week rather than this quarter. A specialist will fix WooCommerce checkout page slow loading faster because they have seen the same twenty causes before and know which order to check them in.
next step
Send us your store URL and a description of when checkout is slow (page load, address change, or both). We reply within 24 hours with what we expect the cause to be, a fixed scope and a fixed price to fix WooCommerce checkout page slow loading on your store, and you deal directly with the engineer doing the work. Contact us here.




