WooCommerce fixes / checkout infinite spinner

WooCommerce Checkout Stuck on an Infinite Spinner? Causes & Fix

The customer clicks Place order, the form greys out, and the spinner never stops. No error, no order, no explanation. Almost always the checkout request never came back — and your browser's Network tab will tell you in about ten seconds which of two very different bugs you have.

Last updated: 16 Jul 2026 · ~7 min read

Quick answer

The usual cause is that the wc-ajax=checkout request never returns — a hook on the checkout process hangs or times out, and because WooCommerce sets no timeout on that request, the spinner spins indefinitely. Open your browser's Network tab and click Place order. A request stuck on pending is a server hang. No request at all is a completely different bug — your gateway's JavaScript.

Which spinner are you actually looking at?

WooCommerce greys the form out the moment you click Place order, then POSTs to wc-ajax=checkout and waits. Every path that ends the wait — success, validation failure, even a server error — removes the overlay. So an overlay that never lifts means the wait never ended: either the response never arrived, or the request was never sent in the first place. That distinction is the whole diagnosis, and it takes one look at the Network tab.

Before you go further, check where the spinner is. A spinner over the order review table — the totals panel on the right, spinning before you click anything — is a different request (wc-ajax=update_order_review) and a different problem. A spinner over the whole form after clicking Place order is the one this guide is about. Owners routinely report the first and get sent to fix the second.

The most common causes (most likely first)

  1. The wc-ajax=checkout request hangs and never returnsNetwork tab shows wc-ajax=checkout stuck on pending — for a minute, for five minutes, forever. Something on the server is blocked: a gateway API call with no timeout of its own, a slow query, or a hook running past PHP's max execution time. WooCommerce sets no timeout on this request, so nothing ever gives up.
  2. The gateway's JavaScript blocked the form and never released itNetwork tab shows no wc-ajax=checkout request at all — and there's a JavaScript error in the console. The form is greyed the instant you click, before any request fires, so a gateway script that intercepts the submit (for 3D Secure, SCA, tokenisation) and then fails leaves you blocked forever. A blocked popup, a CSP rule blocking the gateway's iframe, or a script that 404s all land here.
  3. It's the order review spinner, not the checkout spinnerThe spinner is over the totals panel and appears before you click Place order — often after changing an address or a shipping option. That's wc-ajax=update_order_review failing, and the Place order button is blocked as a side effect.
  4. The order was placed and the redirect target is hangingThe order is sitting in WooCommerce → Orders, but the customer's spinner never went away. The checkout succeeded and returned a redirect; the order-received page then timed out or fatalled. Payment may well have been taken — treat this as a money problem, not a checkout problem.
  5. A fatal error is corrupting the responseThe browser console logs Unable to fix malformed JSON. A PHP warning, notice or fatal has printed into the response alongside WooCommerce's JSON. Check WooCommerce → Status → Logs and your server's PHP error log for a fatal at that exact timestamp.
  6. You're on the block checkout, so it isn't wc-ajax at allNetwork tab shows a POST to /wp-json/wc/store/v1/checkout instead. The block checkout uses the Store API, so the endpoint, the error handling and the log entries are all different — don't go hunting for a wc-ajax request that will never exist.

Where to look first

Spinner gone but not sure what hung it?

The frustrating part of an endless checkout spinner is that the store reports nothing — no error notice, no failed order, no log line saying "a customer waited ninety seconds and left". You only find out when someone emails you, and by then the Network tab evidence is gone. DiagnosticIQ's free dashboard watches the checkout path continuously and flags a checkout request that stops completing, so a hung hook or a broken gateway script surfaces as an alert instead of as a week of quietly abandoned carts. It also catches the version of this that leaves orders placed but unpaid.

Get the free plugin

Made by Prima Digital — the team behind this guide. Free forever; no card to install.

How to know you fixed it

Verify

Place a real test order end to end: the form should unblock and land you on the order-received page, and the wc-ajax=checkout request in the Network tab should complete with a 200 in a second or two rather than hanging.

Frequently asked

Was the customer charged while it was spinning?

Possibly. Check your gateway dashboard for a charge at that timestamp, and WooCommerce → Orders for a matching order. If money moved but no order exists, treat it as a failed-order-but-charged case and don't refund until you've checked.

Why doesn't it just time out and show an error?

Because WooCommerce sets no timeout on the checkout request. A server error that actually returns does unblock the form and show a message — it's the request that never returns at all that spins forever.

It works for me but not for customers. Why?

Usually caching or the gateway's own script. Test in an incognito window as a logged-out customer with a real address and the same payment method — admin sessions bypass page caching and often behave differently.

Should I just disable plugins one at a time?

Look at the Network tab first. Whether a request fires at all tells you if it's a server problem or a browser one, and that halves the plugins worth testing before you touch a live store.

>_
John O'Keane — Founder, Prima Digital · LinkedIn
Contributions by David Zhang · LinkedIn
I build DiagnosticIQ, the WooCommerce diagnostic plugin, and I've learned the hard way that an endless checkout spinner is two completely different bugs wearing the same coat.