Attribution

Short answer: GA4 and Shopify revenue differ because Shopify records every order on its server, while GA4 only counts purchases the browser tag successfully reports. Consent refusals, ad blockers, UPI and payment redirects, third-party checkouts, COD edits, refunds, timezones and currency settings all widen the gap. Reconcile by order ID, not totals, and treat Shopify as the revenue source.

GA4 vs Shopify sales mismatch: why the revenue never agrees and how I reconcile it, cover

The question arrives in almost every first call with a Shopify brand: GA4 says one revenue number, Shopify says another, and the founder wants to know which is right. Shopify is right about revenue. GA4 is a sample of what the browser managed to report. Shopify's own help centre page on analytics discrepancies says to expect differences between Shopify Analytics and third-party tools such as Google Analytics. The useful question is not whether the numbers match, but whether the gap is stable and explained. This piece lists the causes I check and the reconciliation method I use. For the specific case of Indian third-party checkouts, I have a separate piece on Shiprocket and GoKwik.

Why the two systems count differently

Shopify records an order on its server when checkout completes. It does not depend on anything running in the shopper's browser. GA4, in a standard setup, receives a purchase event only if the tag loads on the thank-you or order status page, the user has not blocked it, consent allows it, and the browser stays open long enough to send it. Shopify's discrepancies page notes that Google Analytics relies on JavaScript and cookies, which Shopify's own reports do not. So GA4 will almost always show fewer purchases and less revenue than Shopify, and the gap is made up of many small losses rather than one big one. The goal of reconciliation is to size each loss, fix the ones that are fixable, and document the rest so the team stops arguing about it every month.

Consent, ad blockers and browsers

If you run a consent banner with Google Consent Mode, users who decline analytics storage do not produce normal GA4 purchase events. Depending on your setup, Google may model some of that behaviour, but modelled data is not the same as order-level data, and it will not match Shopify's count. I cover the Indian context in the piece on Consent Mode v2 and the DPDP Act. Ad blockers and privacy-focused browsers block requests to Google's collection endpoints, and the share of users running them varies a lot by audience; tech-savvy and desktop-heavy audiences block more. A server-side GTM setup on your own subdomain can reduce, but not remove, this loss, and it should still respect consent. The practical test is to compare the GA4 purchase count against Shopify orders split by device and browser. If one segment has a far bigger gap than the others, that is where to look.

Payment redirects, UPI, COD and third-party checkouts

Indian checkouts add their own losses. With UPI and many payment gateways, the shopper leaves your site to authorise payment in an app or a gateway page. If they do not return to the order status page, because the app did not redirect, they closed the tab or the connection dropped, the GA4 purchase event never fires, even though Shopify records a paid order. COD orders behave differently: the order is placed, so GA4 counts it, but it may be cancelled or returned later, which GA4 does not know about unless you send a refund. Third-party checkouts such as GoKwik or Shiprocket's checkout replace Shopify's checkout pages, so the purchase event depends entirely on how that provider fires GA4 events, and duplicate or missing purchases are common. I deliberately keep that topic in the dedicated Shiprocket and GoKwik piece, but in a reconciliation I always split orders by checkout and payment method first.

Refunds, edits, timezones and currency

Some mismatches are definitional. Shopify's sales reports deduct returns and adjust for order edits on the date they happen; GA4 keeps the original purchase unless you send a refund event. Shopify reports may show gross sales, net sales or total sales, which include or exclude discounts, shipping and taxes differently, while GA4's purchase revenue is whatever value your tag sends. Decide which Shopify figure you compare against and make the GA4 value match it, for example subtotal after discounts, excluding shipping and tax. Timezone is the next trap: Shopify uses the store's timezone and GA4 uses the property's reporting timezone. If one is set to IST and the other to a US zone, daily totals will never line up, even if monthly ones roughly do. Currency is the last one: if the store sells in multiple currencies, check that the event sends the presentment currency with the matching value, and remember GA4 converts to the property currency using its own exchange rates, which will differ slightly from Shopify's.

How I reconcile: by order ID, not totals

Comparing totals tells you there is a gap, not why. I reconcile at order level. Export Shopify orders for a closed period, at least two full weeks, with order ID, created time, payment gateway, checkout source, device where available and subtotal. Export GA4 purchase events for the same period with transaction_id and revenue, via an exploration report or BigQuery. Join on order ID. That gives you three buckets: orders in both, orders only in Shopify, and transactions only in GA4. The Shopify-only bucket, split by payment method and checkout, shows where tracking drops. The GA4-only bucket usually reveals duplicates, test orders or a transaction_id that does not match Shopify's order name. For orders in both, compare values to catch shipping, tax or currency mistakes. After the first pass, set an expected match rate for your store and check it monthly. A sudden change after a theme, app or checkout update is your early warning.

Which number to use for what

Once the gap is understood, the roles are simple. Shopify is the source of truth for revenue, orders, returns and anything finance reports. GA4 is the source for behaviour: which channels, landing pages and journeys lead to purchase, using the share of orders it does see. Ad platforms have their own attribution and their own numbers again. For channel decisions, I would rather use a blended view, total revenue from Shopify against total spend, and use GA4 and platform data to explain movements within it. The piece on blended versus incremental ROAS covers that framing. What I do not do is try to force GA4 to equal Shopify by inflating events or importing every order. A stable, explained gap is healthy. A gap nobody can explain is the problem.

Sources

Shopify Help Center, Analytics discrepancies: https://help.shopify.com/en/manual/reports-and-analytics/discrepancies

FAQ

There is no universal number, and I would be wary of anyone quoting one. Shopify's help centre simply says to expect discrepancies. Measure your own match rate by order ID, then watch for changes rather than chasing a target.

Yes. Duplicate purchase events from a thank-you page reload, a third-party checkout firing twice, test orders, or values that include shipping and tax can all push GA4 above Shopify. Reconciling by transaction ID exposes these quickly.

It narrows the gap from ad blockers and lost redirects, especially if the purchase is sent from an order webhook. It will not remove gaps from declined consent, refunds or definitional differences, and it should not be used to bypass consent.

If GA4 revenue is used in reporting, yes. Send a refund event with the transaction ID when an order is refunded or an RTO is confirmed, otherwise GA4 will keep counting revenue Shopify has already reversed.

Read this article on your favourite platform

Ready to build the system?

If this describes your funnel, a 30-minute call will find where the constraint sits in your own numbers and what it would take to fix it.

It starts with a 30-minute call. Pick a time below.

Choose a time

Prefer email?