WooCommerce Checkout Slow? How I Diagnose the Real Cause
WooCommerce checkout is slow because it's a dynamic, uncacheable page that fires cart-fragment AJAX, gateway scripts, shipping and tax lookups, session writes, and plugin code on every request. I diagnose checkout by measuring it separately from the rest of the store, then tracing each blocking call back to its source.
WooCommerce checkout is slow because it's a dynamic, uncacheable page that fires cart-fragment AJAX, gateway scripts, shipping and tax lookups, session writes, and plugin code on every request. I diagnose checkout by measuring it separately from the rest of the store, then tracing each blocking call back to its source. If I were checking this on a real site, I'd start with the page that earns traffic or money, confirm whether the issue is backend, frontend, content, or layout related, then apply one fix at a time.
What makes a WooCommerce checkout slow?
A slow WooCommerce checkout is a dynamic page that recalculates totals, shipping, tax, sessions, and gateway data on every single request, so it can't lean on the page cache the rest of your store uses. That's the whole problem in one sentence. Your product archives and blog posts get served as cached HTML in milliseconds, but cart, checkout, and My Account are personal to each shopper, so WooCommerce regenerates them live every time.
I treat checkout as its own machine, not part of the site. When a homepage loads fast and checkout crawls, people assume the store is fine and the customer's connection is bad. It's almost never that. The checkout is doing real work the homepage never does: it talks to Stripe or PayPal, asks your carrier for live rates, runs tax math, writes a session row, and refreshes the cart total in the corner of the screen. Every one of those is a place where seconds leak.
If you want the broader picture of why dynamic stores behave like this, my guide on why WordPress is slow covers the caching model that checkout deliberately opts out of. This page is about diagnosis: finding which of those live calls is actually costing you the time.
How do I know it's checkout and not the whole store?
You know it's a checkout problem when the product page scores green and the checkout page is the only one that stalls, spins on "Place order," or takes a beat before the total updates. Those are checkout-specific symptoms, and they point at different causes than a slow homepage does.
Here's what I watch for. The cart total flickers or lags a second after someone adds an item. The page sits blank after clicking "Place order" while the gateway responds. Shipping options take a visible pause to appear when an address is entered. The checkout itself feels heavier than every other page in a speed test. Each of those maps to a specific culprit, which is why I never test product pages and call it a day.
Testing only the homepage is the single most common mistake I see, and it hides the real issue completely. Cached pages always look great. The uncached ones are where money is lost. Run your checkout through the same lens I use in the WordPress speed audit checklist and you'll see the gap immediately.
Why can't WooCommerce checkout be cached?
Checkout can't be cached because a small set of cookies ties the page to one specific shopper, and serving a cached copy would hand their cart, address, and session to the next visitor. WooCommerce's own documentation is firm on this: cart, checkout, and My Account must never be full-page cached. So the page rebuilds from scratch on every load.
This is where I find the most damage, and it usually isn't WooCommerce's fault. It's a misconfigured cache plugin. Someone enables aggressive caching, forgets the exclusions, and either checkout breaks or it gets served stale and shows wrong totals. The fix is to exclude the right URLs and cookies, not to cache harder. I always exclude the /cart/, /checkout/, and /my-account/ paths, plus the woocommerce_cart_hash, woocommerce_items_in_cart, and wp_woocommerce_session_ cookies, and the wc-ajax and add-to-cart query strings.
Roughly one in seven checkout slowdowns I look at trace back to caching done wrong, not caching done too little. If your cache plugin offers a WooCommerce preset, use it, then verify it actually excluded those paths. For the safe way to wire this up, see my cache plugin settings guide, which keeps dynamic pages dynamic on purpose.
Are cart fragments slowing down your checkout?
Cart fragments are a built-in WooCommerce AJAX call that refreshes the mini-cart total without reloading the page, and on many stores it fires on every page across the whole site, not just where it's needed. That request is ?wc-ajax=get_refreshed_fragments, and it's one of the most common hidden taxes on store speed.
Here's the decision rule I use. If your theme shows a live cart count in the header on every page, fragments run everywhere, and that's an uncached AJAX hit to PHP on each load. If your cart icon is just a static link, you don't need fragments running on pages that aren't the cart. I disable or scope cart fragments on non-cart pages, then keep them on cart and checkout where the live total genuinely matters. Perfmatters has a one-click toggle for this, or a small functions snippet does it.
I treat fragments as guilty until proven necessary because the win is real and the risk is low. Just don't kill them on the cart page itself, or the "add to cart" experience breaks. I go deeper on the trade-offs and the exact snippet in my cart fragments guide.
How much does payment gateway JavaScript cost?
Payment gateways load their own JavaScript and often call out to their servers during checkout, and on a default modern store that script weight is larger than most owners realize. The block-based checkout, default for new installs since WooCommerce 8.3 in late 2023, ships around 300kB of React-powered JavaScript, roughly triple the old shortcode checkout.
Stripe, PayPal, and Klarna each inject their SDK so they can render card fields and validate securely. That's necessary, but it's also a chunk of script and a network round trip you can't always defer. What I can do is stop loading those gateway scripts everywhere else. By default many gateway plugins enqueue their JS on every page, not just checkout. I dequeue gateway and checkout-only scripts from pages where they don't belong, which trims the rest of the site without touching the checkout flow.
Use Query Monitor or your browser's network tab to see exactly which scripts load on checkout and where they come from. If you find the same gateway JS on your blog and product pages, that's free weight to remove. My guide to unused JavaScript in WordPress walks through scoping scripts to the pages that actually use them.
Are live shipping and tax lookups blocking checkout?
Live shipping rates and external tax services make real-time API calls during checkout, and a slow carrier or tax endpoint will stall the page while WooCommerce waits for an answer. This is the gap most checkout guides skip, and it's often the biggest single delay on stores that use real-time rates.
When you offer live rates from UPS, FedEx, USPS, or a plugin like Table Rate with remote logic, every address change can fire a request to that carrier. If their API is slow that day, your checkout is slow that minute, and there's nothing on your server to blame. The same goes for automated tax services like Avalara or TaxJar that call out per order. I test this by switching temporarily to flat-rate shipping and disabling external tax, then re-measuring. If checkout snaps back to fast, I've found my bottleneck.
The fix isn't always to remove live rates, it's to cache them where the plugin allows, reduce how often they fire, or pick a faster provider. Address autocomplete services count here too. Any third-party lookup that runs mid-checkout is a candidate. When the server itself is the slow part instead, my TTFB optimization guide covers tightening response time before these calls even start.
Is your database dragging the checkout down?
A bloated database slows checkout because every order reads and writes session data, postmeta, and order records, and a cluttered wp_options or overloaded Action Scheduler queue adds query time to that work. Stores accumulate orphaned metadata, expired transients, and stale session rows that never get cleaned up.
The high-impact move here is enabling High-Performance Order Storage. HPOS moves order data out of the bloated wp_posts and wp_postmeta tables into dedicated order tables built for the job. WooCommerce reports order processing running several times faster with it on, and recent releases keep trimming checkout query counts, with WooCommerce 10.7 cutting checkout queries from 204 to 172 on an uncached load. After that, I clean transients, clear stale wp_woocommerce_sessions rows, and check that Action Scheduler isn't choking on tens of thousands of pending tasks, which a poorly behaved plugin can cause.
I run Query Monitor on a live checkout to see the slowest queries and how many fire, because guessing at database problems wastes time. For the full cleanup routine including HPOS and session tables, see my WooCommerce database optimization guide, and for store-wide gains, the WooCommerce speed optimization service page lays out the whole stack.
Do plugins and hosting decide checkout speed?
Plugins and hosting decide more of your checkout speed than any other factor, because every active plugin runs its code on the uncached checkout page and your server processes all of it live with no cache to hide behind. This is where slow stores get slow and stay slow.
On checkout, plugin quality matters far more than plugin count. A single poorly coded extension that adds queries or external calls on the checkout hook can cost more than ten lightweight plugins combined. I selectively disable non-essential plugins on a staging checkout, measure each time, and rank them by impact. The ones that touch the checkout hook get the hardest look. Page builders, popups, chat widgets, and review plugins rarely need to run on checkout at all.
Hosting sets the floor. If your server's Time to First Byte on checkout sits above 600ms, the host is your primary bottleneck and no plugin tuning will rescue it, since checkout can't be cached to mask a slow server. I'd rather a store on real WooCommerce hosting with 300ms TTFB than a cheap shared plan with a stack of optimization plugins. My slow hosting guide covers how to tell when the server is the wall you're hitting.
How do I diagnose a slow checkout step by step?
I diagnose a slow checkout by measuring the checkout page in isolation, then peeling back one live call at a time until the slow one shows itself. Diagnosis beats guessing every time, and the order matters because each step rules out a layer.
My exact sequence: first, measure cart and checkout separately from the rest of the store, with real products in the cart, because an empty checkout tells you nothing. Second, check TTFB on the checkout URL to see if the server is the problem before anything else. Third, run Query Monitor on a live checkout to spot slow queries and heavy hooks. Fourth, open the network tab and watch for the cart-fragments AJAX call and gateway scripts loading where they shouldn't. Fifth, temporarily switch to flat-rate shipping and disable external tax to expose carrier and tax API delays. Sixth, disable non-essential checkout plugins one group at a time and re-measure.
By the end of that loop I know whether it's the host, the database, a gateway, a shipping lookup, a cache misconfiguration, or one bad plugin. Then I fix the specific thing instead of throwing every optimization at the wall. Once the cause is clear, my speed up WooCommerce checkout guide is the fix-side companion to this diagnostic one. You can also run the checkout URL through my free site audit tool to get a starting read.
What checkout metrics actually matter?
The metrics that matter for checkout are server response time and the time real shoppers wait, not the lab score of a page they never see in that exact state. Checkout is interactive and personal, so I weight server-side and interaction timing over a synthetic LCP number.
I aim for TTFB under 600ms on checkout, and ideally under 400ms on a tuned store, because that's pure server work you can't cache away. I watch INP, since checkout is where people actually type and click, and a target under 200ms keeps the form feeling responsive. Total checkout load under 2 to 3 seconds is the practical benchmark most fast stores hit. I care less about a perfect PageSpeed score on checkout than I do about "Place order" responding quickly, because that's the moment a sale either completes or dies.
Measure before and after every change so you know what worked, and always with items in the cart. For the wider Core Web Vitals context that frames these numbers, see my WordPress Core Web Vitals guide. Speed here isn't vanity. A slow checkout directly raises abandonment, so this is the page where milliseconds turn into revenue.
My checklist for WooCommerce Checkout Slow
Measure cart and checkout separately.
Review payment and shipping API calls.
Check cart fragments and sessions.
Inspect database and Action Scheduler load.
Disable non-essential checkout scripts for testing.