Guide
Why GA4 revenue doesn't match Shopify
By Metricby · Updated
GA4 revenue doesn’t match Shopify for three different reasons, and they need different fixes. Some orders never reach GA4. Some reach it with a different amount (tax, shipping, discounts, refunds, currency). Some land on a different day (time zone, processing delay, refund dates). A single percentage mixes all three together. If you match orders by transaction ID, the gap splits into those three parts, and you can see which one is yours.
Most explanations stop at a list of causes and a “normal” range. The ranges quoted online vary from 5–30% to 10–50%, and none of them comes with a method. Your own gap depends on your audience, your checkout and your setup. Splitting it tells you how much of it is real tracking loss and how much only comes from comparing different numbers.
Step 1: Make sure you’re comparing the same number
Shopify and GA4 both say “revenue”, but they mean different things.
Shopify reports several sales figures (Shopify: sales reports):
| Shopify metric | What it contains |
|---|---|
| Gross sales | Product price × quantity, before taxes, shipping, discounts and sales reversals |
| Net sales | Gross sales − discounts − sales reversals (returns, refunds, other negative adjustments) |
| Total sales | Net sales + taxes + duties + shipping charges + fees |
GA4’s Purchase revenue is “the sum of revenue from purchases … minus any refunds given”. Tax and shipping are separate metrics, Tax amount and Shipping amount (Google: dimensions and metrics). What counts as revenue comes from the value your setup sends with each purchase. Google’s own example sets it to the sum of price × quantity for all items, with tax and shipping as separate parameters (Google: measure ecommerce).
So the GA4 figure is closest to Shopify’s net sales, if your setup sends the discounted product total as value. Setups differ, though, and you shouldn’t assume. Calibrate with one order:
- Pick a recent order with shipping and, ideally, a discount.
- In GA4, open Explore → Free form. Add the dimension Transaction ID and the metrics Purchase revenue, Shipping amount and Tax amount. Find that order.
- Compare with the order page in Shopify.
In our test store, an order with $24.95 of products and $8 shipping showed $24.95 purchase revenue and $8 shipping amount in GA4. For that setup, the right comparison is Shopify’s net sales, not total sales. If your GA4 purchase revenue equals the order total instead, compare it with total sales. Comparing GA4 with the wrong Shopify figure creates a gap that isn’t a tracking problem.
Step 2: Match the orders and split the gap
Now compare order by order for a closed date range: one that ended at least two days ago, since GA4 can take 24–48 hours to process data (Google: data freshness). Export your Shopify orders, list GA4 purchases by transaction ID, and match the two lists. Our guide on missing purchases walks through each step.
Every Shopify order then falls into one of three groups, and the gap splits with them:
| Group | What it means | Where it comes from |
|---|---|---|
| Missing | The order has no GA4 purchase | Ad blockers, declined consent, express checkout, a broken tag |
| Different value | The order is in GA4, but with a different amount | Tax and shipping, discounts, refunds, currency, edited orders |
| Timing | The order is in both, on different days | Time zone, refund dates, processing delay |
Then check GA4 for transaction IDs that aren’t in Shopify, or that appear more than once. Those inflate GA4 (see the end of this guide).
An example. Say Shopify shows $10,000 total sales for a week and GA4 shows $8,300 purchase revenue. That’s a 17% gap. After matching:
- Missing: 9 orders worth $1,150 never reached GA4.
- Different value: $780 is shipping and tax, which are in Shopify’s total sales but not in GA4’s purchase revenue.
- Different value, the other way: $350 of refunds that Shopify deducted and GA4 never received. They make GA4 higher.
- Timing: $120 of orders placed late Sunday evening, which GA4, on another time zone, put into the next week.
Only the missing orders, $1,150 (11.5%), are tracking loss. The rest comes from comparing different numbers, and fixing tags will never close it. Note also that the refunds hide part of the loss: in the total alone, $350 of missing revenue is invisible.
Missing orders
These are orders that never reached GA4. The usual causes are ad blockers and privacy browsers, declined cookie consent, express checkout (Shop Pay, PayPal, Apple Pay, Google Pay), and a tag that stopped running. Each leaves its own pattern in the list of missing orders: payment method, country, a start date.
We cover how to read those patterns and fix each cause in Why GA4 isn’t tracking all your Shopify purchases.
Also remove orders that never pass through the online checkout before you compare: draft orders you mark as paid, POS sales, and orders from third-party checkouts. GA4’s purchase tracking doesn’t see them, and they aren’t a tracking failure.
Same order, different value
The order is in GA4, but the amounts differ. Compare a few of these orders line by line. The difference usually matches one of these:
- Tax and shipping. The difference equals the order’s shipping or tax. You’re comparing with the wrong Shopify metric (see Step 1).
- Discounts. The difference equals the discount. Shopify’s net sales are after discounts (Shopify: sales reports). If your setup sends the price before the discount, GA4 will be higher.
- Refunds and cancellations. Shopify deducts them as sales reversals. GA4 only knows about a refund if your setup sends a
refundevent with the order’s transaction ID (Google: measure ecommerce). Many setups don’t, so GA4 keeps the full amount of orders you refunded. - Currency. If you sell in several currencies, GA4 converts each purchase into the property’s currency using the exchange rate from the day before the transaction (Google: currency reference). Shopify’s conversion differs, so small differences per order are normal. A purchase sent without a
currencydoesn’t get its revenue computed correctly. - Edited orders. If you add or remove items after checkout, Shopify updates the order. GA4 keeps what was sent at the time of purchase.
- Revenue of zero. If an order is in GA4 with no revenue at all, the
valueorcurrencyparameter is missing. That’s a setup problem. See the purchase event’s parameters.
Same order, different day
Both tools have the order, but they assign it to different days, so short date ranges don’t match.
- Time zone. GA4 uses the time zone in Admin → Property details. Shopify uses the one in Settings → General. If they differ, orders near midnight land on different days.
- Processing delay. GA4 can take 24–48 hours to finish processing (Google: data freshness). “Yesterday” isn’t final yet.
- Refund dates. Shopify records a refund on the day it’s processed, not on the original order’s date (Shopify: sales reports). A refund this week lowers this week’s net sales for an order placed last month.
Timing differences mostly even out over longer ranges. If a monthly comparison still shows a gap, timing isn’t the cause.
When GA4 shows more than Shopify
Sometimes GA4 revenue is higher. Look for transaction IDs in GA4 that don’t match a Shopify order, or that appear twice:
- Duplicate purchase events. Two setups send the same purchase, for example the Google & YouTube app plus your own tag. A reload of the thank-you page, or a return from a payment redirect, can also fire it a second time.
- Test orders. Shopify leaves test orders out of its sales reports (Shopify: sales reports). If test checkouts ran on your live store, GA4 may still have counted them.
- Refunds GA4 never heard about, as described above.
Duplicates have their own causes and fixes. We’ll cover them in a separate guide.
Making the numbers match
Once you’ve split the gap, you know what to do with each part:
- Value and timing differences: fix your comparison, not your tracking. Use the matching Shopify metric, the same time zone, closed date ranges, and longer periods. If refunds matter to you, make sure a
refundevent reaches GA4. - Duplicates: keep one source per event and remove the rest.
- Missing orders: this is the real tracking loss. Part of it can be fixed in the browser. Ad blockers, declined consent and fragile checkout hand-offs are limits of browser-side tracking that no tag setting removes. Some apps close that gap by sending each completed order to GA4 independently of the visitor’s browser.
Use Shopify for financial reporting and GA4 to understand where sales come from. Whichever setup you choose, re-run the order-level comparison afterwards. It’s the only way to see which part of the gap closed.
How we made this guide: written by the Metricby team, which tested these scenarios over several weeks on a Shopify development store, across checkout types, consent choices and browsers.