WooCommerce Checkout Stuck Loading: Causes and How to Fix It

When a WooCommerce checkout page gets stuck on an endless loading spinner, customers cannot complete purchases, calculate shipping, or view available payment gateways. Because this glitch directly interrupts transactions, resolving it quickly is critical to preventing lost revenue and cart abandonment.

Quick Answer: How to Fix a Stuck WooCommerce Checkout

An endless checkout spinner usually indicates that an asynchronous JavaScript (AJAX) request to the ?wc-ajax=update_order_review endpoint has failed, stalled, or returned invalid data. Follow these quick troubleshooting steps to identify and resolve the failure:

  • Inspect Browser DevTools: Open the Network and Console tabs to inspect the update_order_review call for JavaScript syntax errors, 403 Forbidden statuses, or 500 Internal Server errors.
  • Match Site URLs: Go to Settings > General in WordPress and verify that WordPress Address (URL) and Site Address (URL) share the exact same protocol (https://) and domain structure (with or without www).
  • Clear and Exclude Caches: Flush all page and server caches. Ensure your caching plugins and CDN bypass dynamic endpoints, specifically the cart, checkout, and any URLs matching /?wc-ajax=*.
  • Test for Plugin/Theme Conflicts: Temporarily activate a default theme (such as Storefront or Twenty Twenty-Four) and deactivate non-essential plugins to catch scripts blocking the checkout DOM.
  • Increase PHP Memory: Raise the WordPress memory limit to at least 256M inside wp-config.php to prevent background processes from crashing during total and tax recalculations.
Error / Symptom Underlying Cause Recommended Fix
AJAX returns -1 or 0 Expired or cached WordPress security nonce Purge page cache and exclude checkout pages from caching layers
HTTP 403 Forbidden on wc-ajax WAF rule, ModSecurity, or Wordfence blocking requests Whitelist the ?wc-ajax=update_order_review endpoint in your firewall
HTTP 500 / 504 on checkout PHP memory exhaustion or database query timeout Increase WP_MEMORY_LIMIT and inspect the PHP error log
Console: Uncaught TypeError Broken script in payment plugin or custom theme Update plugins, disable JS minification/deferral, or swap theme
AJAX returns HTML instead of JSON PHP notices outputted or rogue index.html file Disable WP_DEBUG_DISPLAY and remove root index.html

How the WooCommerce Checkout Loading Process Works

To understand why the spinner hangs, it helps to understand what happens under the hood. During checkout, WooCommerce calculates shipping rates, taxes, coupon discounts, and payment methods dynamically.

Whenever a customer alters their billing address, selects a shipping method, or inputs a coupon, WooCommerce triggers a background AJAX request to the endpoint:

https://example.com/?wc-ajax=update_order_review

While this request is executing, WooCommerce overlays a CSS loading spinner across the #order_review container to prevent user input. The server processes the customer's input, recalculates totals, generates a fresh security nonce, and returns a JSON payload containing updated HTML fragments. Once the browser receives a valid JSON response, the JavaScript script replaces the order review fragments and removes the loading class, hiding the spinner. If that communication cycle breaks, the loading overlay never clears.

Common Causes of a Stuck Checkout Page

According to WooCommerce documentation on endless loading spinners, the problem typically stems from one of five architectural areas:

  • Mismatched Site URLs: Discrepancies between your configured site address and home address trigger browser Cross-Origin Resource Sharing (CORS) blocks on AJAX requests.
  • JavaScript Exceptions: An unhandled script error from a payment gateway, marketing pixel, or minifier stops execution before the loading overlay can be toggled off.
  • Aggressive Caching and Stale Nonces: When static page caching stores checkout nonces, the server rejects subsequent AJAX calls with a validation failure (returning -1).
  • Firewall or Security Interception: Web Application Firewalls (such as Cloudflare WAF, ModSecurity, or security plugins) may flag rapid background requests from the checkout form as malicious. If your store sits behind an edge proxy that struggles to communicate with your origin, you may encounter connectivity bottlenecks similar to those covered in our guide on Cloudflare Error 522 (Connection Timed Out).
  • Server-Side Script Hangs or PHP Limits: If your server runs out of PHP execution time or memory while evaluating shipping zones, third-party carrier APIs, or database queries, the worker thread terminates prematurely. If server databases become unreachable altogether, review our walkthrough on WordPress Error Establishing a Database Connection.

Step-by-Step Diagnostic and Resolution Guide

Step 1: Inspect the Browser Network and Console Tabs

Before modifying files or disabling extensions, run a targeted browser diagnostic to find the exact failure point:

  1. Open your store in Google Chrome, Mozilla Firefox, or Microsoft Edge.
  2. Add a test product to your cart and navigate to the Checkout page.
  3. Right-click anywhere on the page and select Inspect (or press Ctrl + Shift + I / Cmd + Option + I).
  4. Navigate to the Console tab and look for red JavaScript error messages. Note down any filenames, plugin folders, or variable references cited in the error stack.
  5. Switch to the Network tab, select the Fetch/XHR filter, and change a field on the checkout form (such as the billing country or zip code).
  6. Locate the request named ?wc-ajax=update_order_review.
  7. Check the Status column and click on the request to inspect the Response tab:
    • If the status is 200 OK but the response displays raw HTML, PHP warnings, or a blank body instead of clean JSON, custom code or output buffering is corrupting the endpoint.
    • If the response is -1 or 0, WordPress failed the nonce authentication check.
    • If the status is 403 Forbidden, a security layer blocked the request.
    • If the status is 500 Internal Server Error, a PHP fatal error occurred on the web host.

Step 2: Verify WordPress and Site URL Settings

Because AJAX requests rely on identical origins, differing protocol schemes (http vs. https) or domain prefixes (example.com vs. www.example.com) will cause browsers to block checkout communications due to CORS policies.

  1. Log in to the WordPress admin panel.
  2. Navigate to Settings > General.
  3. Compare the WordPress Address (URL) and Site Address (URL) fields.
  4. Ensure both fields match character-for-character, including https://.
  5. Save changes if you made any corrections.

If these settings are locked or greyed out in your dashboard, check your wp-config.php file using an FTP client or hosting file manager. Ensure the following constants use matching URLs, as outlined in the WordPress documentation on wp-config.php:

define( 'WP_HOME', 'https://yourdomain.com' );
define( 'WP_SITEURL', 'https://yourdomain.com' );

Step 3: Exclude WooCommerce Dynamic Pages from Caching and CDNs

Caching pages that contain unique user sessions or dynamic security tokens causes stale data collisions. When a cached checkout page is served to multiple shoppers, their nonces fail validation, returning -1 on subsequent updates.

  • Plugin Page Exclusions: Open your caching plugin settings (such as WP Rocket, LiteSpeed Cache, W3 Total Cache, or WP Super Cache) and verify that the following URL paths are excluded from static caching:
    • /cart/
    • /checkout/
    • /my-account/
  • Query String Bypass: Ensure your caching engine does not cache requests containing query strings, particularly ?wc-ajax=*.
  • Disable JS Minification/Deferral on Checkout: If your caching plugin bundles or defers JavaScript files, exclude WooCommerce core scripts (woocommerce.js, checkout.js, accounting.js) or disable script concatenation entirely on checkout templates.
  • Cloudflare Page Rules / Cache Rules: If using Cloudflare, create a Cache Rule to set Bypass Cache for URI paths matching /checkout/* and /*wc-ajax=*.

Step 4: Check for Plugin and Theme Conflicts

Third-party plugins—especially custom checkout field editors, outdated payment gateways, or multi-currency switchers—often inject faulty JavaScript or hook into woocommerce_update_order_review_fragments with fatal PHP exceptions.

To safely test for conflicts without disrupting live shoppers:

  1. Install and activate the official Health Check & Troubleshooting plugin from WordPress.org.
  2. Navigate to Tools > Site Health > Troubleshooting and click Enable Troubleshooting Mode. This simulates a vanilla environment exclusively for your logged-in administrator session while visitors see the standard store.
  3. Under the admin bar troubleshooting menu, keep WooCommerce active and switch the theme to a default theme (such as Storefront or Twenty Twenty-Four).
  4. Test the checkout page. If the spinner clears immediately and order calculations work normally, the issue is caused by your theme or an active plugin.
  5. Enable your plugins one by one from the troubleshooting menu until the spinning wheel reoccurs. The last activated extension is the source of the conflict.

Step 5: Increase PHP Memory Limit and Prevent Script Output

WooCommerce officially recommends a minimum WordPress memory limit of 64 MB, but modern stores with several active extensions frequently require 256 MB or 512 MB during checkout recalculations.

To increase your allocation, open your wp-config.php file located in the root WordPress directory and add the following directive before the /* That's all, stop editing! Happy publishing. */ line:

define( 'WP_MEMORY_LIMIT', '256M' );

Additionally, unhandled PHP notices and deprecated warnings printed directly to the browser will break WooCommerce's JSON parser. To capture errors in a private log file without outputting them onto the screen, configure proper logging constants as documented in the WordPress guide to debugging:

// Enable debugging and error logging
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
@ini_set( 'display_errors', 0 );

After reproducing the issue on checkout, check /wp-content/debug.log to inspect any recorded exceptions or fatal stack traces.

Step 6: Review Server Directory Overrides and Web Application Firewalls

If the update_order_review call returns an HTTP 403 or unexpected HTML, check your server configuration:

  • Check for index.html in the Root: If a static index.html file exists in your website's root directory, some web servers will serve it instead of passing AJAX requests to index.php, returning raw HTML to the checkout script. Remove the static file or ensure your web server directory index priorities prioritize index.php.
  • Inspect Firewall Activity Logs: If your store uses ModSecurity, Wordfence, or an edge WAF, inspect the blocked request logs for entries corresponding to wc-ajax. Create an allowlist rule for legitimate POST and GET traffic directed at WooCommerce endpoints.

Verification Checklist

Once you have applied the necessary fixes, verify that your checkout flow is fully operational across various devices and scenarios:

  • Open a private/incognito browser window to ensure no cached session cookies or admin tokens interfere with testing.
  • Add both standard and variable products to your cart and proceed to checkout.
  • Change the destination address (country, state, and postal code) and verify the loading spinner displays briefly before updating shipping methods and tax rates.
  • Apply and remove a coupon code to ensure order total fragments refresh seamlessly.
  • Select each enabled payment gateway to confirm that integrated card fields render properly.
  • Perform a complete end-to-end test transaction using a test gateway or sandbox mode.

When to Contact Hosting Support

If you have ruled out plugin conflicts, confirmed URL matching, and bypassed caching, but the checkout endpoint still returns HTTP 500, 502, 504, or 403 status codes, reach out to your web hosting support team. Provide them with the following details to speed up resolution:

  • The exact URL where the issue occurs (e.g., https://yourdomain.com/checkout/).
  • The exact failing endpoint and HTTP status code from your browser Network tab (e.g., ?wc-ajax=update_order_review returning 500 Internal Server Error).
  • Timestamp and time zone of your most recent test request.
  • A request to inspect the server's Nginx/Apache error logs, PHP-FPM error logs, and ModSecurity/WAF audit logs for blocked requests or memory allocation errors.

Frequently Asked Questions

Why does the checkout spinner only hang for returning customers or logged-in users?

This typically occurs when user session handling fails in the database (e.g., in the wp_woocommerce_sessions table) or when an authentication nonce generated for a logged-in user role is cached by an external object cache or reverse proxy. Clearing expired WooCommerce transients via WooCommerce > Status > Tools > Clear customer sessions often resolves this issue.

Can third-party payment gateways cause an endless loading spinner?

Yes. Many modern payment gateways (such as Stripe, PayPal Payments, or Square) load hosted iframe elements and execute client-side tokenization. If the gateway cannot reach its API due to an invalid API key, outdated SDK, or strict Content Security Policy (CSP), the script will hang and prevent the order review container from finishing its render cycle.

Does switching to the WooCommerce Checkout Block fix this issue?

The WooCommerce Checkout Block uses modern REST API endpoints rather than the legacy wc-ajax=update_order_review endpoint. Switching to the Checkout Block can bypass older jQuery-based plugin conflicts. However, if the underlying problem is server-side timeouts, REST API blocking, or site URL mismatches, those issues will still need to be resolved.

Sources & References

Comments

Popular posts from this blog

Cloudflare Error 522 (Connection Timed Out): Causes and How to Fix It

Shopify Checkout Not Working: Causes, Diagnostics, and Fixes