TL;DR
Purchases get tracked obsessively and refunds get ignored, which means most GA4 properties report gross revenue and call it net. The correction path on Magento 2 runs through credit memos: the document Magento creates when money goes back, whatever route it takes. The WeltPixel GA4 PRO extension makes Refund a selectable Measurement Protocol event, sent server-side when a credit memo is created [4]. This piece covers what GA4 requires on a refund event, how Magento's credit memo model differs from a simple refund button, what the extension documents and what it does not, and why your ad platforms will still not show corrected numbers no matter what you do here.
Key Takeaways
- GA4's
refundevent requires atransaction_idthat matches the original purchase. No match, no correction [1]. - Refund tracking through the Measurement Protocol is a PRO-tier feature, triggered by Magento credit memos and sent server-side [4].
- The Measurement Protocol timestamps an event at receipt unless the sender explicitly backdates it, and backdating is capped at 72 hours. Either way a refund issued weeks after the order lands in the current period, not the order's [2].
- Adobe documents three refund methods against a credit memo: online through the payment processor, offline, and (on Adobe Commerce) account credit such as Store Credit [3].
- Per-item and partial refund payload behavior is not covered in the extension's documentation. Verify it against your own store before you build reporting on it [4].
- Check the event list of whichever server-side ad platform addon you run: those lists are forward-funnel, so ad platform conversion values stay gross regardless of what GA4 shows.
- Version 1.15.7 (September 2, 2025) fixed refund events being sent from the default store regardless of which store issued them, so multi-store operators should be on a current version [4].
The arithmetic nobody runs
Run the arithmetic on an illustrative store. GA4 reports 200,000 in revenue for the month. The refund rate, measured in Magento where the credit memos actually live, is 8 percent, so 16,000 of that was returned to customers. Paid media spend for the month was 40,000.
Reported ROAS: 5.0. Real ROAS: 4.6.
That gap does not sit evenly across campaigns. Refund rates cluster by category, by size-heavy apparel lines, by acquisition source, and by the campaigns that push discount-led first purchases. So the campaigns most likely to be over-credited are frequently the ones already being scaled on the strength of that credit.
Fixing it does not require a new analytics stack. It requires that a refund event reaches GA4 with the right transaction ID, and that somebody has decided who is responsible for issuing credit memos in a way that consistently produces one.
What GA4 will accept as a refund
The spec is small. GA4's ecommerce reference defines refund as the event signifying that one or more items were refunded to a user. transaction_id is required, value and currency are required for revenue metrics to compute correctly, and Google recommends including item information if you want item-level refund metrics in reports [1].
Two consequences follow, and both are more operational than technical. First, the transaction ID your refund event carries has to be the same string the original purchase carried. If your purchase events send the Magento increment ID and something later sends an entity ID, GA4 receives a refund for a transaction it has never heard of.
Second, timing, and the mechanism here is worth stating exactly because it gets described wrongly. The Measurement Protocol timestamps an event at receipt unless the sender explicitly backdates it. Backdating is capped at 72 hours; past that, GA4 either clamps the timestamp to 72 hours ago or rejects the event outright, depending on validation behavior [2]. Either way a refund issued weeks after the order lands in the current period, not the order's. Month-over-month revenue comparisons need to account for that. A related boundary, if you also run client-side tracking: Measurement Protocol events meant to be joined with client-side events should arrive within 48 hours of the original client-side timestamp [2].
This part of the specification is shared across platforms rather than Magento-specific. The Shopify server-side GA4 refund tracking guide walks the same GA4 requirements from the other side, and the mechanism it describes for capturing refunds does not transfer here, which is the subject of the next section.
Why credit memos are the trigger, not "a refund"
Magento does not have a single refund action. It has a document type.
A credit memo is the record of a refunded amount against an order. Adobe documents three refund methods against a credit memo: online through the payment processor, offline, and (on Adobe Commerce) account credit such as Store Credit [3]. For tracking purposes the split that matters is gateway call versus no gateway call. An offline refund is what you use when the money went back some other way: a bank transfer, or a payment method that does not support programmatic refunds.
All three produce a credit memo. That matters for tracking, because the credit memo is the object your analytics layer can observe. The WeltPixel GA4 PRO extension's Refund event is sent through the Measurement Protocol off the credit memo [4], and what a partial memo does with that trigger is part of what the docs do not cover. If a customer service agent refunds a customer through the payment gateway's own dashboard and never records a credit memo in Magento, no refund event exists, and the extension has nothing to react to. That is a process failure that looks exactly like a tracking bug, and it is worth ruling out first when refunds are missing.
Magento's own model also explains a second thing. Adobe's own workflow puts invoice generation ahead of the credit memo: on Authorize you must invoice first, on Authorize and Capture the invoice already exists [3]. Stores with unusual invoicing workflows should confirm their sequence produces the document at all.
What does the extension actually document about refunds?
The documented surface is clear on the following points [4]:
- Refund tracking through the Measurement Protocol is PRO only. The STANDARD tier's client-side dataLayer has no equivalent, and there is a structural reason: nobody is browsing your storefront when a refund is issued.
- Refund is one of the selectable Measurement Protocol track events, alongside Purchase and the funnel events, configured at
Admin → WeltPixel → GA4 PRO → Enable Measurement Protocol Tracking Configuration. - Refund events are sent server to server, so the visitor's browser and ad blockers are irrelevant to delivery. The extension can log the Consent Mode v2 state alongside each Measurement Protocol event to
var/log/ga4.logif you need it for attribution debugging [4]. - Version 1.15.7, released September 2, 2025, fixed multi-store setups where refund events were sent from the default store regardless of which store initiated them [4]. Multi-store operators on older versions should treat that as a reason to upgrade before trusting per-store refund figures.
Here is the boundary, stated plainly because the alternative is guessing. The behavior of partial refunds and per-item refund payloads is not covered in the extension's documentation [4]. GA4's own reference recommends item information for item-level refund metrics [1], but what a partial credit memo produces in practice is not something the documentation specifies, and we are not going to assert it.
So verify it on your own store before you design reporting around it. Issue a partial credit memo on a test order, enable the file log at var/log/ga4.log, and read the payload the extension actually sent. That takes ten minutes and replaces an assumption with a fact about your own configuration and version. If refund events are not showing up at all, the walkthrough on fixing events not being tracked when using the Measurement Protocol covers the general diagnostic path.
Your ad platforms are still reporting gross
One paragraph, because it changes what you can conclude from any of this.
GA4 has a refund event. The ad platforms do not work that way. Each server-side addon in this stack documents its own event list, and those lists are built around the forward funnel: views, cart, checkout, purchase. Read the event list of whichever addon you run and you will not find a refund in it. So the conversion values those platforms report stay gross unless you correct them with the platform's own tooling. Meta and TikTok have no refund event; Google Ads has a separate conversion-adjustment path that works nothing like server-side event firing. Correcting GA4 gives you an accurate analytics property and a place to measure real ROAS. It does not correct the numbers the bidding algorithms see, and if anything it widens the gap between GA4 and your ad platforms, which is a reporting conversation worth having with whoever reads those dashboards before you turn refund tracking on.
How do you reconcile GA4 against Magento?
Magento holds the authoritative record, so reconciliation starts there.
Start from Magento, not GA4. Pull the credit memo total for a period from the Magento reports or directly from the sales tables. That figure is the truth. Then compare it to the negative revenue GA4 recorded for the same period, remembering the timing shift from the 72-hour boundary discussed above [2].
Three gaps and what each one means:
- GA4 shows less refunded revenue than Magento. Either refund events are not enabled in the Measurement Protocol configuration, or some refunds happened without a credit memo, or transaction IDs are not matching.
- GA4 shows refunds Magento does not. Check for test orders and for duplicate sends, and check whether an order was credited twice through separate memos.
- Totals match, timing does not. Expected behavior. Refunds land in the period they were issued.
The order grid column marking which orders were sent through the Measurement Protocol is the fastest way to check the purchase side of this ledger, and it is filterable [4]. For a fuller treatment of matching GA4 revenue to Magento sales figures, the guide to accurate sales data via the Measurement Protocol covers the purchase half of the same reconciliation.
FAQ
Does refund tracking work on the STANDARD version of the extension?
No. Measurement Protocol tracking, including the Refund event, is a PRO-tier feature. The client-side dataLayer has no refund path, since refunds happen in the admin rather than in a shopper's browser [4].
What triggers a refund event on Magento 2?
The creation of a credit memo. Adobe documents three refund methods against one: online through the payment processor, offline, and account credit such as Store Credit on Adobe Commerce. All three produce the credit memo the extension reacts to, while a refund issued in the payment provider's dashboard with no credit memo in Magento produces no event at all [3][4].
Do partial refunds send item-level data to GA4?
The extension's documentation does not specify partial refund or per-item payload behavior, so test it on your own store with the file log enabled rather than assuming either answer. GA4's own reference recommends including item information when you want item-level refund metrics [1][4].
If your Magento store counts refunded orders as revenue in GA4, the WeltPixel Google Analytics 4 PRO extension sends Refund server-side off the credit memo, alongside the Purchase events it already tracks. Enable it, issue one test credit memo, and read var/log/ga4.log before you trust the number.
Sources
- Google Analytics, "Recommended events" (GA4,
refund), https://developers.google.com/analytics/devguides/collection/ga4/reference/events - Google Analytics, "Measurement Protocol: Sending events" (event timestamping and 72-hour backdating), https://developers.google.com/analytics/devguides/collection/protocol/ga4/sending-events
- Adobe Commerce, "Credit Memos", https://experienceleague.adobe.com/en/docs/commerce-admin/stores-sales/order-management/credit-memos/credit-memos
- WeltPixel Google Analytics 4 User Guide, https://docs.weltpixel.com/GA4/User-Guide-WeltPixel-Google-Analytics-4.html