Full Answer
The single most effective fix is passing a unique transaction_id parameter with every purchase event. According to Google's ecommerce documentation (developers.google.com), GA4 will silently ignore a second purchase event that carries the same transaction_id — but only from the same user in the same session. That built-in guard won't help if you're double-tagging from multiple sources or if page refreshes generate new session context.
The biggest WooCommerce-specific cause is plugin stacking. Running Google Site Kit alongside GTM4WP, or having your theme's built-in tracking active while a dedicated plugin also fires, means the same order triggers two or more independent purchase events — each with its own data layer push (seresa.io). The fix is straightforward: pick one tracking method and fully disable every other source. Use GA4's DebugView or Google Tag Assistant to verify only one purchase tag fires per order.
Thank-you page reloads are the other persistent offender. Every time a customer refreshes the order confirmation page, the purchase event fires again. You can prevent this by setting a browser cookie or sessionStorage flag after the first fire, or — better — by moving to server-side tracking that captures the event at order creation rather than at page load (Simo Ahava). Server-side approaches also dodge ad-blocker interference and don't depend on the customer's browser behavior at all.
Finally, never send an empty string as the transaction_id. Google Analytics will deduplicate all events carrying transaction_id="", effectively collapsing your entire revenue into one transaction (Google Analytics Help). Use the WooCommerce order number — it's unique by default and customer-anonymous.