Why it happens
The browser did not send the purchase. GA4 counts a purchase when the shopper's browser sends it. Ad blockers stop the Google tag from loading. Safari and other privacy-focused browsers limit what it can store. A shopper who pays and leaves before the confirmation page is done never fires the event. Each of these orders is paid in Shopify and absent in GA4.
The shopper declined analytics cookies. Where a cookie banner asks for consent, a shopper who declines analytics may not be measured, or may be measured with less detail. The order exists in Shopify, and GA4 sees little or nothing of it. Stores that sell in regions with consent rules usually see a bigger gap there.
Duplicates hide the loss. A purchase sent twice with different transaction IDs, or sent with no transaction ID at all, raises the GA4 count again. The total can then look close to Shopify while single orders are missing and others appear twice. That is why a matching total does not prove the data is right.
Other causes are smaller but real. The GA4 property may use a different time zone than the store, so an order paid late in the evening lands on different days in the two systems. Revenue in GA4 depends on what value the tag sends, for example item prices without shipping or tax, while Shopify's total includes them. Refunds and cancelled orders may also be handled differently, so compare paid orders with paid orders and refunds on their own line.
Check it yourself
- 1In GA4 Admin, open the property's details and read the property's time zone. In Shopify admin > Settings > General, read the store's time zone. If they differ, expect the day boundaries to differ.
- 2In GA4 > Reports > Monetization > Ecommerce purchases, set the last 7 full days and read the purchases and the purchase revenue. Leave out the last two days or expect them to change.
- 3In Shopify admin > Orders, filter by Sales channel, keep the online store, set the same days and count paid orders. Leave out point of sale, draft orders marked as paid and subscription renewals.
- 4In GA4 > Explore, start a Free form exploration. Add the dimension Transaction ID and the metrics Ecommerce purchases and Purchase revenue. Set the same date range.
- 5Read the list. GA4 removes repeat purchases that share a transaction ID from the same user, so a duplicate usually arrives with a different ID or none. Compare the number of transaction IDs with your order numbers for the same days; more IDs than orders points to a second sender. An order number from Shopify that is missing from the list is a lost purchase. Check a handful of orders from your Shopify list by hand.
- 6In your consent tool, check how many shoppers declined analytics cookies in the same period.
- 7Compare the gap with the share of declines and the share of mobile and Safari traffic in GA4 > Reports. A gap that these explain is browser loss. A gap with more transaction IDs than orders points to a duplicate sender.
When the missing purchases are the ones browsers never send, why server-side tracking fixes missing purchases explains the other route.
FAQ
Should GA4 and Shopify match exactly?
No. They measure differently and in different time zones. A gap is normal. A gap that changed suddenly, or more transaction IDs than orders, are worth chasing.
Why is revenue different even when purchases match?
GA4 revenue is whatever value the tag sends. Shopify revenue includes shipping, tax and discounts in their own ways.
Does the Explore report show every order?
It shows what GA4 stored. Some reports apply thresholds or sampling, so for a small set of orders use Free form with a short date range.
Can a duplicate and a loss cancel out?
Yes. Two missing orders and two repeated ones give a correct total and wrong details, which is why you compare IDs and not just totals.