Premium Themes

Handcrafted Beautiful Bootstrap HTML Templates for your Business Website.

WooCommerce Customer Charged Twice? How to Find and Prevent Duplicate Orders and Double Charges

By Alex Carter | | 8 min read

Few emails damage trust faster than “You charged my card twice.”

Double charges are rarely caused by one dramatic bug. They come from ordinary things: a slow checkout, an impatient click, a firewall that retries a request, a payment plugin that times out and tries again. Each one is rare. Across hundreds of orders a month, they add up, and each one that goes unnoticed becomes a refund request, a chargeback, or a one-star review.

This guide covers what causes duplicate orders in WooCommerce, how to find every one in your store, how to refund them without breaking your records, and how to prevent them.

Two different problems that look the same

It helps to separate two situations:

  1. Duplicate orders: two WooCommerce orders for the same basket. The customer may have been charged once or twice.
  2. Duplicate charges: the customer’s card was charged twice. There may be one order or two.

The worst case is a second charge with no matching order at all. WooCommerce has nothing to show you, so you only find it in your gateway dashboard, or when the customer’s bank statement arrives.

What causes double charges in WooCommerce

Four causes of WooCommerce double charges: a double click on Place order, a page refresh or Back on the payment step, a firewall or proxy replaying the request, and a payment plugin retrying after a timeout. All are made worse by a slow checkout.

Multiple clicks on “Place order”

On a slow checkout, shoppers click again. WooCommerce’s classic checkout blocks the form while it processes, but slow pages, custom themes, page builders and some checkout plugins can weaken that protection. A second click can create a second order and, depending on the gateway, a second payment.

The page was refreshed or the back button was used

A shopper who refreshes on the payment step, or goes back and resubmits, can create a second order with an identical basket.

Request replays by a firewall, proxy or host

Some firewalls, CDNs and reverse proxies resend a POST request when the first one is slow to respond, assuming it failed. If your checkout takes several seconds (often because of third-party API calls for tax, shipping rates or fraud checks), the replayed request can process as a brand-new checkout. Sucuri, in particular, has published guidance on configuring it for WooCommerce for this reason.

Payment plugin retries after a timeout

If the gateway responds slowly, a payment plugin may treat the request as failed and retry. If the first attempt actually succeeded, the customer is charged twice.

Subscription renewal retries

Renewal logic that retries a “failed” payment which actually went through can create two renewal orders and two charges.

One transaction ID attached to two orders

Occasionally a plugin conflict attaches the same gateway transaction to two different orders. You see two “paid” orders but only one payment. This inflates your revenue reports and can lead to shipping two parcels for one payment.

How to find every duplicate charge

Step 1: Look for near-identical orders

In WooCommerce → Orders, sort by date and look for the same customer email, same total and same items within a few minutes of each other. On a small store this is tedious. On a busy store, it isn’t realistic to do by hand every week.

Step 2: Check transaction IDs

Open each suspected pair and compare the gateway transaction IDs. Two orders with the same transaction ID usually means one payment, two orders. Two orders with different transaction IDs means two real payments.

Step 3: Compare against the gateway

Search your Stripe or PayPal dashboard for the customer’s email. Count the successful payments for that basket and compare against the orders in WooCommerce. This is the only way to catch a second charge that never produced an order.

Step 4: Check your logs

‘WooCommerce → Status → Logs’ and your server access logs can show whether two checkout requests arrived close together. That tells you whether it was the shopper, a replay, or a plugin retry, and that decides the fix.

How to refund a double charge without breaking your records

Decision tree: if two similar orders share a transaction ID, it's one payment and two orders, so cancel the extra order. If they have different IDs, it's two real payments, so refund the duplicate from the WooCommerce order via the gateway. If there's no second order, check the gateway for a charge with no order.

The cleanest fix keeps WooCommerce and your gateway in agreement:

  1. Decide which order to keep. Usually the first one.
  2. Refund the duplicate from inside WooCommerce, using the Refund button on the duplicate order and choosing Refund via gateway. This sends the refund to the gateway and records it in WooCommerce, so stock, revenue and reports stay correct.
  3. Avoid refunding only in the gateway dashboard. A refund made directly in Stripe or PayPal may never be recorded in WooCommerce. The order still looks paid, your revenue is overstated, and stock may be wrong. (See how to reconcile WooCommerce with Stripe and PayPal.)
  4. Make sure the duplicate isn’t shipped. Once fully refunded, the order should move to Refunded. A fully refunded order still sitting in Processing is a classic way to ship an order you didn’t get paid for.
  5. Tell the customer. Let them know it was spotted, refunded, and how long their bank usually takes to show it.

How to prevent duplicate orders

  • Speed up checkout. The slower the checkout, the more people click twice and the more likely a proxy replays the request. Audit plugins that call external APIs during checkout.
  • Don’t break the built-in submit protection. If you’ve customized the checkout or use a page builder, test what happens when you double-click Place order on a slow connection (browser DevTools can throttle the network).
  • Review your firewall and CDN. Make sure nothing retries POST requests to checkout or payment endpoints.
  • Keep your gateway plugin updated. Retry and idempotency handling improves over time.
  • Test with block checkout and classic checkout separately if you’ve switched between them.
  • Monitor continuously. Prevention reduces duplicates. It doesn’t eliminate them.

Catch duplicates automatically

Ordafide Order Integrity for WooCommerce is a free plugin that scans your recent orders and flags problems in plain sentences, sorted by money at risk. Its Duplicate charge check looks for:

  • one gateway payment reference attached to two orders, and
  • the same customer charged twice for an identical basket within minutes.

It also runs a Refund mismatch check that catches orders marked Refunded with no refund record, refunds larger than the order total, and fully refunded orders still marked Processing, so a refunded duplicate doesn’t get shipped anyway.

The duplicate window and other thresholds are configurable, findings you’ve reviewed can be ignored, and the plugin never captures, refunds or voids a payment. Everything runs on your own server.

The one case a store-side scan can’t see is a charge with no order. Ordafide Pro covers it with read-only reconciliation against Stripe, PayPal, Square, Mollie and Razorpay, flagging money with no order, paid orders with no payment, and amount disagreements.

Frequently asked questions

Why did my customer get charged twice on WooCommerce?
Usually a double click on a slow checkout, a page refresh during payment, a firewall or proxy replaying the checkout request, or a payment plugin retrying after a timeout.

How do I refund a duplicate WooCommerce payment?
Refund it from the duplicate order in WooCommerce using Refund via gateway, so the refund is recorded in both systems.

Can a customer be charged twice with only one WooCommerce order?
Yes. If the second charge’s order was never created, WooCommerce shows nothing. Only comparing against the gateway, manually or with a reconciliation tool, will find it.

Does WooCommerce prevent duplicate orders on its own?
It has basic protection against repeat form submission, but it can’t stop request replays, plugin retries or every theme customization. Monitoring is the reliable safety net.

We have updated our Privacy Policy and Cookies policy