# GA4 Refund Tracking for WooCommerce: The Missing Half of Revenue Accuracy > Purchases flow into GA4, refunds never do — so reported revenue drifts upward forever. How GA4's refund event works, why almost nobody sends it, and how to wire it correctly. *Source: https://plugins.viglan.com/ga4-refund-tracking-woocommerce/* Ask a store owner if their GA4 tracks purchases and you’ll get a confident yes. Ask about refunds and you’ll usually get silence. The result is systematic: GA4 revenue drifts upward relative to reality, month after month, and every ROAS decision made on it is slightly wrong in the expensive direction. ## Why refunds matter more than they look Typical WooCommerce refund rates run 2–8% (far higher in apparel). If you spend on ads with a target ROAS, an 8% overstatement of revenue is an 8% overstatement of every campaign’s performance — enough to keep a losing campaign alive for quarters. Refund tracking is not bookkeeping pedantry; it is what makes your ad optimization honest. ## How GA4’s refund event actually works GA4 has a first-class `refund` event with two modes: - **Full refund:** send `transaction_id` only — GA4 reverses the whole transaction. - **Partial refund:** send `transaction_id` plus the refunded `items` (with quantities) and `value` — GA4 subtracts precisely. The one hard requirement: the `transaction_id` must exactly match the original purchase’s. If your purchase used the order *number* and your refund uses the order *ID* (not always the same in WooCommerce!), GA4 records an orphan refund that reverses nothing. ## Why almost nobody sends it Refunds happen in wp-admin, not in the customer’s browser. There is no thank-you page, no GTM container running, no dataLayer — the entire client-side tracking stack is absent at the moment the refund exists. So the event must originate **server-side**: hook WooCommerce’s refund creation, build the payload from the refund object, and send it via the Measurement Protocol. Snippet-based setups structurally cannot do this, which is why the refund event is the clearest dividing line between pasted-in tracking and engineered tracking. ## Wiring it correctly (the checklist) 1. **Hook the right event:** WooCommerce’s refund hook fires for both full and partial refunds — inspect the refund object rather than assuming full. 2. **Reuse the purchase’s transaction_id source.** Whatever produced the purchase ID (order number, usually) must produce the refund’s. Centralize it in one function. 3. **Send refunded items for partials** with per-line quantities from the refund object, and the refund’s value with the same tax basis as your purchases. 4. **Mind the API secret:** Measurement Protocol needs your GA4 API secret server-side. Keep it out of the browser and out of git. 5. **Verify in DebugView:** refund a €1 test order and watch the event arrive with matching transaction_id. Then check the Monetization report a day later — the revenue should visibly step down. ## The compounding payoff Once refunds flow, three things quietly improve: ROAS becomes truthful, LTV cohorts stop overcounting serial refunders, and finance stops asking why GA4 and the bank disagree. It is one of the highest leverage/effort ratios in the whole analytics stack. *TrackPilot wires the whole pipeline for you — spec-compliant GA4 events for WooCommerce including one-per-order purchases and refunds, with Consent Mode v2. [See TrackPilot →](https://plugins.viglan.com/plugins/trackpilot-for-woocommerce-ga4-gtm-tracking-pro/)*