Pull up your GA4 property and check the refund amount for last month. For most ecommerce stores, that number is zero, or close to it. Now pull the same month from Shopify's Returns report. It is probably not zero. It is probably somewhere between 10% and 40% of orders, depending on what you sell. That gap between the two numbers is your real ecommerce return rate problem, and it has nothing to do with how many customers actually send things back.
Both numbers can be true at the same time, and that gap is the whole problem. GA4 isn't under-reporting returns because your return rate is unusually low. It's reporting close to nothing because almost nobody wires the one event that would make it show up at all.
- NRF and Happy Returns put the 2025 online return rate at 19.3%, against 15.8% for retail overall, and apparel runs well above both (illustrative range, see below).
- GA4 has refund metrics but no built-in way to populate them. Someone has to send a
refundevent with the original transaction ID, and Shopify does not do this automatically. - Every return that never reaches your reporting stack keeps counting as revenue it already took back, which quietly inflates ROAS and contribution margin until the gap gets reconciled.
The benchmark your dashboard isn't checked against
Return rate benchmarks vary enough by category that a single blended number is close to useless on its own. The NRF and Happy Returns 2025 Retail Returns Landscape report put the overall online return rate at 19.3% of online sales for 2025, against 15.8% for retail sales overall, a gap driven mostly by shoppers buying sizes and colors they cannot try on first and by platforms that make returns frictionless by design.
Inside that blended number, the spread by category is wide, though the category-level splits below are illustrative ranges aggregated across industry trackers rather than a single audited figure. Apparel and footwear sit at the top, commonly cited in the 20-40% range, driven almost entirely by fit uncertainty. Electronics run lower, typically 8-15%, often tied to buyer's remorse or a product that did not match expectations. Categories like beauty and food sit toward the bottom, since they are rarely purchased for fit and often not returnable once opened.
The practical use of a benchmark like this is not bragging rights. It's a sanity check. If your category typically runs 25% and your internal number reads 4%, the problem is very unlikely to be that your products fit better than everyone else's. It's far more likely that your reporting isn't catching every refund, your store is miscategorizing returns as exchanges, or the return window hasn't closed yet on recent orders.
Why GA4 shows almost nothing
This is the part most return-rate benchmark roundups skip entirely, because they stop at the percentage and never touch the plumbing that is supposed to report it.
GA4's ecommerce measurement model includes a dedicated refund event, and Google's own developer documentation is specific about what it needs: the original transaction_id from the purchase, plus one or more items identified by item_id and quantity if you want item-level refund data. Send that event correctly, and GA4 populates three metrics: refund amount, refunds, and item refund amount. Don't send it, and those three metrics sit at zero indefinitely, no matter how many orders actually come back.
The catch is that nothing in a standard Shopify or WooCommerce setup sends that event by default. Shopify's native analytics connection fires the purchase-side events end to end, view_item, add_to_cart, begin_checkout, purchase, but refunds processed through the Shopify admin don't automatically trigger anything that reaches GA4. The standard fix is to listen on the refunds/create topic in Shopify's webhooks API, capture the refund amount and the original order ID server-side, and forward a matching refund event to GA4 through the Measurement Protocol, so it lands against the same transaction_id the original purchase event used. Nobody does this by default because it isn't part of any starter tracking template, which is exactly why return rate ends up as the blind spot almost every GA4 setup carries without anyone noticing.
The same gap exists on the ad platform side. If your Meta or Google Ads conversion value never adjusts down for a refunded order, the platform keeps optimizing and reporting against revenue that already came back. Our ecommerce tracking audit checks specifically for this: whether refund and cancellation events exist anywhere in the stack, or whether every reporting surface is quietly running on gross, pre-return numbers.
What an unmeasured return rate actually costs you
A missing refund event isn't a cosmetic reporting gap. It directly overstates two numbers founders look at every week: ROAS and contribution margin.
Say a category-typical 20% of orders come back, and none of that ever reaches GA4 or a profit model. Gross ad-attributed revenue is counting orders that are no longer real revenue, because the model still treats the refunded order as money earned. A campaign reporting a 3.5x ROAS on paper might be closer to 2.8x once refunded orders are subtracted back out, a 20-point drop in gross terms that is actually a 25% overstatement relative to the real 2.8x number, which is the difference between a campaign worth scaling and one quietly burning cash. The same distortion runs through contribution margin: our ecommerce profit reporting breakdown covers the full waterfall from revenue to CM3, and returns are one of the line items in that waterfall that gets skipped most often, right alongside payment fees and fulfillment cost.
The timing makes this worse heading into November. Return volume spikes in the weeks after Black Friday and Cyber Monday as gift purchases and impulse buys come back, which means a store with an unmeasured return rate going into BFCM is about to watch its post-holiday numbers look artificially strong for a few weeks before the refunds catch up and the real picture shows up late. Our BFCM tracking checklist covers the duplicate-event and revenue-mismatch risks that show up during the sale itself; return rate tracking is the piece that determines whether the weeks after BFCM tell you the truth or a delayed, inflated version of it.
How to actually fix the tracking
- Check what GA4 is showing right now. Open Explore, build a free-form table filtered to the
refundevent over the trailing 90 days. If it returns nothing, the event has never fired, regardless of what your store's own return rate looks like. - Pull the real number from your store. In Shopify, use the Returns report (or Orders report filtered to refunded status) to get actual refund count and value for the same window. That is your real return rate until GA4 is fixed.
- Wire the refund webhook. Set up a listener on Shopify's
refunds/createwebhook that captures the order ID and refund amount, then forwards arefundevent to GA4's Measurement Protocol carrying the original transaction_id, so it reconciles against the matching purchase event rather than floating as an orphaned record. - Push the adjustment to ad platforms too. Confirm Meta and Google Ads conversion values get decremented (or the conversion removed) when an order refunds, so platform-reported ROAS isn't optimizing against revenue that no longer exists.
- Segment return rate by SKU and campaign, not just store-wide. Once the event is flowing, the real value is finding which products or which ad creative are driving disproportionate returns, not just confirming the top-line percentage.
Most of this is a half-day of server-side work once someone actually looks for the gap, which is the part that tends to get skipped because nothing about a missing refund event throws an error. Everything just keeps reporting a number that happens to be wrong. If you want a second set of eyes on whether your own return rate is actually reaching your reporting stack, a fixed-scope reporting audit checks it alongside the rest of the revenue reconciliation, with a sample report at /services/audits/samples/reporting showing exactly what that looks like before you book one.
