start here: the two numbers were never going to match
GA4 counts purchase events fired by a browser. Shopify counts orders. Those are different things, and on most stores they are different by a few percent before anything is wrong. If you go straight to debugging you will spend a day chasing a gap that your order mix explains on its own.
So the first job is a baseline: subtract the orders that could never have fired a browser event, and see what is left. If the remainder is still off, that is the part worth debugging, and the rest of this page covers how.
Written by Andrew Maury. I run the free tracking scanner and the paid audit, and the figures lower down come from my own scan of 192 Shopify storefronts. Last reviewed 9 October 2026, against Shopify's current checkout and pixel behaviour.
jump to: what's normal · what's actually broken · how to check, in order · FAQ
how much of the gap is normal
I am not going to give you a percentage. Shopify and Google don't publish one, and the numbers you'll find quoted around (5 to 10 percent, 10 to 20, up to 30) are asserted with no method behind them. The honest answer is that it depends on your order mix, and you can work yours out in about ten minutes.
Orders that never had a browser session
None of these can fire a GA4 purchase event, because no one loaded a page:
- POS orders. In-person sales through Shopify POS.
- Draft and manual orders created in the admin, including invoices and phone orders.
- Subscription rebills. Recurring charges through Shopify Subscriptions, Recharge and similar never load a checkout. On a subscription-heavy store this is the whole gap on its own.
- Marketplace and channel orders. Amazon, eBay, Faire, Walmart, Instagram and Facebook Shops, TikTok Shop, the Shop app, and B2B or wholesale orders.
- Orders created by an app or the Admin API, including ERP pushes and replacement orders raised by a returns app.
- Post-purchase upsells and order edits that add line items or spawn a second order.
Orders where the session existed but the hit didn't arrive
- Ad blockers and tracking protection. uBlock, Brave, Safari ITP and Firefox ETP all block requests to google-analytics.com.
- Declined consent under basic consent mode, where tags are held until someone accepts and nothing is sent before that.
- Offsite payment redirects. PayPal, Klarna, Afterpay, iDEAL. Most customers do come back to the confirmation page, so size this smaller than your share of orders paid that way.
- Someone closing the tab the moment payment clears.
Two things people blame that aren't the cause
- Refunds and cancellations do not reduce your GA4 purchase count. A refund is a separate event. They affect revenue comparisons, and they affect the Transactions metric, but the purchase event count stays where it was. Your Shopify order count also still includes cancelled orders unless you filter them out, so this one can push either way.
- Attribution windows do not change the total. They change which channel gets credit. If your totals disagree, attribution settings are not why.
One that is worth checking in five seconds
Timezones. GA4 reports in the property's reporting timezone, Shopify Analytics in the store's timezone. If they differ, orders slide between days. Compare a window of 28 days or more so a day-boundary shift stops mattering.
what's actually broken, when something is
Two installs of the same tag, both live
The usual way a store ends up counting a purchase twice. Shopify's own setup sends the event, and a GA4 app, a theme snippet or an old agency's tag sends it again. Both carry the same measurement ID, so GA4 has no way to tell the second one is a copy.
On 5 October 2026 I scanned 192 well-known DTC Shopify brands I picked myself. 63 of them fired the same page view twice. My scan doesn't place orders, so I can't tell you from it how often a purchase gets doubled. What it does show is how often a store has two live installs of one tag, which is the setup that produces a doubled purchase.
Two GA4 properties collecting the same traffic
Same problem one level up: two different measurement IDs, usually an old agency's property that nobody removed when the new one went in. Each property records its own copy of the order, so neither one agrees with Shopify and neither one agrees with the other.
33 of those same 192 stores were running two or more of their own GA4 properties at once. The raw detector flagged 45 before exclusions. I removed a tracking vendor's own property appearing on 10 stores through first-party subdomains, four template placeholder IDs that were never filled in, one pixel that loaded a second ID and never sent a hit, and one embedded video player's own property.
Nothing firing a purchase at checkout at all
The tag works on your product pages and there is no route for it to fire at checkout, so GA4 only ever hears about the orders where something else picked it up. Since the checkout changes below, this is now an easy state to end up in by accident.
42 of the 133 stores where my scan reached checkout had a tag live on storefront pages and no sign of it at the cart or checkout step. I record that as likely rather than confirmed: a server-side send is invisible from outside the store, so some of those 42 are tracking fine in a way I can't see.
what these numbers are and aren't
One scan, one day, 192 storefronts I chose because they are well known. Not a random sample of Shopify, so read them as "this is common among brands you've heard of," not as a rate across all stores. The scan reads public pages only: it never signs in, never places an order, and can't see anything sent server-side. Counts above are recomputed from the stored evidence with the current detector rather than quoted from the run.
how to check, in order
- Pull both counts over 28 days or more, and check the two timezones. Shopify Admin > Orders, filtered to the range. In GA4 go to Reports > Engagement > Events, find the
purchaserow and read Event count. Don't use Monetization > Ecommerce purchases for this. That report is item-scoped, so a three-line order counts as three. Don't use the Transactions metric either: Google's definition of it includes refund events. - Subtract the orders that could never fire a browser event. Filter the Shopify order list by sales channel and pull out POS, draft and manual, subscription rebills, marketplace and B2B. What's left is the number GA4 could in principle have seen. Compare against that, not against your total.
- Match on
transaction_id, not on totals. Export your orders and left join them against GA4 purchases. First confirm which value GA4 is actually sending: the order name (#1001) or the numeric order ID. Comparing the wrong field makes perfectly good tracking look broken, and this catches more people than any other single thing here. Matching also tells you which orders went missing, which is where the pattern usually shows up. - If GA4 is over the adjusted baseline, look for a second install. DebugView or Tag Assistant is the reliable route: place a test order and watch whether one purchase arrives or two.
If you'd rather watch the Network tab, two things will trip you up. gtag batches events into a single POST to
/g/collectwith the event name in the request body, so typingen=purchaseinto the filter box matches nothing. Use Cmd-F or Ctrl-F inside the Network panel instead, which does search bodies. And set the type filter to All, because some hits leave via sendBeacon with resource typepingand the Fetch/XHR filter hides them. Theen=andgcs=parameters are stable and widely relied on, but Google doesn't document them, so treat them as observed rather than specified. - Work through every place a GA4 ID can live. There are seven: app pixels under Settings > Customer events; custom pixels in the same screen; the Google & YouTube channel app; hardcoded gtag or GTM in theme code; apps injecting script tags or theme app extensions; a server-side GTM container or Measurement Protocol send; and any GTM container holding its own GA4 configuration tag. Check custom pixels first. Shopify removed the old Google Analytics and Meta fields from Online Store > Preferences in February 2025 and auto-migrated what was in them into custom pixels. A lot of stores are carrying a second tag there that nobody consciously installed.
- If GA4 is under the adjusted baseline, check how a purchase reaches GA4 at all. Theme code and additional scripts no longer run on the thank-you or order status page for anyone: that sunset on 28 August 2025 for Plus and 26 August 2026 for everyone else. Three routes are left, and you need at least one of them: an app pixel subscribing to
checkout_completed, a custom pixel, or a server-side send. If you have a post-purchase extension installed,checkout_completedcan fire on the post-purchase page rather than the thank-you URL. Looking only at the thank-you page will tell you it's broken when it isn't. - Rule consent in or out properly. Under advanced consent mode a declined visitor still sends a cookieless ping, so the tag did fire. Under basic consent mode nothing is sent at all until someone accepts, and those orders are simply gone from GA4. Check which you're running in Tag Assistant, or read the
gcsparameter on the request. DebugView won't tell you: it shows events and parameters, not consent state, and with analytics storage denied the event may not reach DebugView in the first place.
the one I'd check first on a store I'd never seen
Custom pixels, under Settings and Customer events. The February 2025 migration moved a lot of old tags into that screen without anyone deciding to put them there, and a store that also installed a GA4 app afterwards now has two installs that look unrelated in the admin. It costs thirty seconds to look, and when it's the answer it's a deletion rather than a rebuild.
or have something else look
The free scanner loads your storefront, cart and checkout pages and reports every tracking ID it sees firing, which covers steps 4 and 5 above without you placing a test order. It reads public pages only, so it can't see server-side sends and it can't reconcile against your orders. Three scans a day per IP. If you want the full comparison against your real order records, that's the $1,750 Tracking & Profit Audit on a fixed 10-business-day turnaround.