If your woocommerce checkout slow loading times are hurting conversions, you do not need generic optimization advice like compressing images. You need to identify the exact database query, external API call, or bloated script blocking the PHP thread during the checkout handshake. This guide walks you through profiling the checkout process and implementing measured, high-impact fixes to reduce checkout load times under two seconds.
Quick answer
- Profile the bottleneck first: Use Chrome DevTools and Query Monitor to see if the delay is in
wc-ajax=update_order_review(usually shipping/tax APIs) orwc-ajax=checkout(usually payment gateway or email triggers). - Implement Object Caching: Install Redis or Memcached to offload transient and session queries from the MariaDB/MySQL database.
- Disable Cart Fragments: Stop
wc-ajax=get_refreshed_fragmentsfrom running on non-cart and non-checkout pages. - Optimize Autoloaded Options: Clean up the
wp_optionstable to ensure WordPress does not load megabytes of unused plugin data on every request. - Defer External APIs: Cache shipping and tax API calculations, and set strict timeouts so slow carrier servers do not hang your checkout.
How to profile a slow WooCommerce checkout
Before changing any configuration, you must isolate whether the bottleneck is database-bound, network-bound (external APIs), or client-side (render-blocking JavaScript).
Use Chrome DevTools Network Tab
Open your checkout page with the DevTools Network tab active. Filter by Fetch/XHR and perform a test checkout. Watch for two primary requests:
wc-ajax=update_order_review: This fires when a user changes their address, shipping method, or payment option. If this takes longer than 500ms, your shipping APIs, tax calculations, or localized checkout fields are blocking.wc-ajax=checkout: This fires when the user clicks "Place Order". If this takes several seconds, the culprit is almost always synchronous payment gateway communication, order status transition hooks, or transactional email generation.
Install Query Monitor Install the Query Monitor plugin on a staging environment. Navigate to the checkout page and inspect the HTTP Requests section. Look for external API calls to UPS, FedEx, Stripe, or tax services like TaxJar. Any external request taking over 200ms needs caching or asynchronous handling.
Check the Database Queries section for duplicate or slow queries. Pay close attention to queries targeting wp_options or wp_usermeta tables.
---
1. Optimize the update_order_review AJAX bottleneck
The update_order_review call runs repeatedly as users fill out the checkout form. If this call is slow, typing an email address or choosing a state feels laggy.
Often, this delay is caused by shipping carrier APIs (like USPS or DHL) fetching live rates synchronously on every keystroke. To fix this, cache your shipping rates using transients so WooCommerce does not query the carrier API on every AJAX refresh.
add_filter('woocommerce_shipper_rates', 'sa_cache_shipping_rates', 10, 2);
function sa_cache_shipping_rates($rates, $package) {
if (empty($package['destination'])) {
return $rates;
}
// Generate a unique key based on the package destination and contents
$package_hash = md5(serialize($package['destination']) . serialize($package['contents']));
$transient_key = 'wc_ship_rates_' . $package_hash;
$cached_rates = get_transient($transient_key);
if (false !== $cached_rates) {
return $cached_rates;
}
// Cache rates for 1 hour to prevent constant API hits during active sessions
set_transient($transient_key, $rates, HOUR_IN_SECONDS);
return $rates;
}
Additionally, set strict timeouts on your external HTTP requests. By default, WordPress allows up to 5 seconds for external API requests. Reduce this to 2 seconds so your checkout does not hang when a carrier API experiences downtime.
add_filter('http_request_args', 'sa_limit_checkout_api_timeouts', 10, 2);
function sa_limit_checkout_api_timeouts($r, $url) {
if (strpos($url, 'api.shipping-carrier.com') !== false || strpos($url, 'tax-api') !== false) {
$r['timeout'] = 2; // Limit to 2 seconds
}
return $r;
}
---
2. Eliminate cart fragments on non-cart pages
WooCommerce uses cart fragments to update the cart widget in the header via AJAX on every page load. This script (wc-cart-fragments.js) triggers an AJAX call to wc-ajax=get_refreshed_fragments, which bypasses page caching and boots the entire WordPress core, slowing down the site.
While this does not directly slow down the checkout page itself, it degrades server performance globally, leaving fewer system resources available when a user reaches the checkout.
Disable cart fragments everywhere except on actual shop, cart, and checkout pages where they are needed:
add_action('wp_enqueue_scripts', 'sa_disable_cart_fragments_selectively', 99);
function sa_disable_cart_fragments_selectively() {
if (function_exists('is_woocommerce')) {
if (is_cart() || is_checkout()) {
return;
}
wp_dequeue_script('wc-cart-fragments');
}
}
Make sure your theme has a fallback link to /cart/ so users can still access their cart if the AJAX mini-cart does not update dynamically on non-shop pages.
---
3. Clean up bloated autoloaded options in the database
On every single page load, WordPress loads all rows in the wp_options table where autoload is set to 'yes'. If this dataset exceeds 1-2MB, database performance drops significantly, directly causing a woocommerce checkout slow experience.
Run this SQL query in phpMyAdmin or via WP-CLI to find the total size of your autoloaded options:
SELECT SUM(LENGTH(option_value)) AS autoload_size FROM wp_options WHERE autoload = 'yes';
If the result is higher than 800,000 bytes (800KB), you must identify the bloated options. Run this query to find the top 10 largest autoloaded rows:
SELECT option_name, LENGTH(option_value) AS value_len
FROM wp_options
WHERE autoload = 'yes'
ORDER BY value_len DESC
LIMIT 10;
Often, you will find old transient data, deleted plugin settings, or massive arrays from page builders. Change the autoload status of unused options to 'no' or delete them if the plugin is no longer installed:
UPDATE wp_options SET autoload = 'no' WHERE option_name = 'problematic_plugin_option_name';
---
4. Offload session data with Redis or Memcached
WooCommerce relies heavily on database-driven sessions to track what is in the cart, customer addresses, and chosen shipping methods. By default, these are stored in the wp_options table as transients or via the wp_woocommerce_sessions table.
Without an object cache, every page load and AJAX update on the checkout page triggers multiple read/write database queries to manage these sessions. Under high traffic, this causes database row locking.
To resolve this, install Redis on your server and configure the Redis Object Cache plugin. This moves transient and session storage out of the physical database and into fast system memory (RAM).
Verify that your wp-config.php has the correct salt keys and that your object cache is active by running this WP-CLI command:
wp cache type
It should return Redis or Memcached. Once active, database queries on checkout will drop by up to 60%.
---
5. Defer payment gateway scripts and optimize transactions
Many payment gateways load heavy external JavaScript libraries (like Stripe, PayPal, or Klarna) on the checkout page. If these scripts are loaded synchronously, they block the browser from rendering the checkout fields.
Ensure your payment gateway integrations are configured to load scripts asynchronously. You can force non-essential scripts to defer using this filter:
add_filter('script_loader_tag', 'sa_defer_payment_scripts', 10, 2);
function sa_defer_payment_scripts($tag, $handle) {
$scripts_to_defer = array('stripe', 'paypal', 'klarna');
foreach ($scripts_to_defer as $script) {
if (strpos($handle, $script) !== false) {
return str_replace(' src', ' defer="defer" src', $tag);
}
}
return $tag;
}
During the final wc-ajax=checkout action, WooCommerce triggers transactional emails to the customer and admin. If your server sends these emails synchronously via PHP mail() or a slow SMTP connection, the checkout spinner will spin until the mail server responds.
Offload email delivery to a dedicated transactional mail service (like Mailgun, SendGrid, or Postmark) using their official API integration rather than SMTP. API calls are significantly faster than SMTP handshakes.
---
Checklist
- Run a baseline speed test on the checkout page using Chrome DevTools to measure
wc-ajaxresponse times. - Check the size of autoloaded options in the database and keep it under 800KB.
- Dequeue the cart fragments script on all pages except the cart and checkout.
- Configure Redis or Memcached to handle object caching for sessions and transients.
- Implement transients to cache shipping carrier API rate calculations.
- Set low timeouts (2 seconds) on external API calls to prevent checkout hangs.
- Defer payment gateway JavaScript files so they do not block page rendering.
- Offload transactional emails to an API-based delivery service instead of standard SMTP.
Frequently asked questions
Why is the WooCommerce checkout page so slow?
The checkout page is usually slow because of unoptimized database queries, slow external API calls for shipping rates and taxes, bloated autoloaded options, or synchronous email sending during the order placement process.
How do I speed up wc-ajax=update_order_review?
Speed up this request by caching shipping carrier rates using WordPress transients, reducing external API timeouts, and disabling unnecessary plugins that hook into the checkout update process.
Does Redis speed up WooCommerce checkout?
Yes. Redis offloads session data and transients from your MySQL database to system memory (RAM). This eliminates slow database queries and prevents row locking when multiple users are checking out simultaneously.
- WooCommerce developer docsWooCommerce developer docs
- WooCommerce documentationWooCommerce documentation
Drafted with AI assistance. Code targets current WordPress, WooCommerce and Next.js APIs; test changes on a staging site before production.