A Shopify store reports 224 orders for the week. GA4 reports 187 purchases. Nobody changed anything. The gap is not random either: it sits at roughly a sixth of orders, week after week.
That shape, a steady fraction rather than a sudden drop, almost always means one checkout path is being tracked and another is not. On Shopify, the untracked path is usually an express checkout: Shop Pay, Apple Pay, Google Pay or PayPal Express.
Why express checkouts are different
A standard checkout walks through contact, shipping and payment pages before landing on the order status page. An express checkout collects address and payment in a wallet sheet and jumps almost straight to the order confirmation. Depending on how your purchase tracking was built, it may be listening for a step that never happens:
- A trigger on the checkout URL path that the express flow skips.
- A dataLayer push from a theme snippet that only runs on the full checkout.
- A legacy "additional scripts" implementation that behaves differently for accelerated checkouts.
The order is real, the money arrives, and the purchase event never fires.
How to prove it is the cause
- Export a week of orders from Shopify with the payment gateway column.
- Pull the same week of purchase events from GA4 with transaction IDs.
- Join on order number. The missing orders will cluster on one or two gateways.
If the missing set is spread evenly across gateways, the cause is something else, most likely consent or a tag firing before the dataLayer is populated.
The fix that holds up
Move purchase tracking to Shopify's customer events, which run as web pixels inside Shopify's checkout sandbox. A pixel subscribed to the checkout_completed event fires for every completed checkout regardless of the path taken to get there, including express wallets and the new checkout. It also carries the full order payload, so revenue, tax, shipping and line items arrive without any theme code.
If you also run Google Tag Manager, you can have the web pixel push a purchase event with the GA4 ecommerce shape to the dataLayer, and keep your GTM tags unchanged. The pixel becomes the single source of the purchase event and the old thank-you-page trigger can be retired.
What to deduplicate
If the old trigger stays live alongside the new pixel, orders that go through the full checkout will be counted twice. Either remove the old trigger, or make both paths send the order number as the GA4 transaction_id, which GA4 uses to deduplicate purchases within a property. Removing the old trigger is cleaner.
Checking it stayed fixed
Reconcile every day, not once. Tracked revenue against Shopify revenue, grouped by gateway, with a tolerance of a few percent for refunds and timing. A gap that reappears on one gateway after a theme or app change is caught the same day instead of the next quarter.
FAQ
Why does GA4 show fewer purchases than Shopify?
The usual causes, in order: a checkout path your tag does not cover (express checkouts), tags blocked by consent for part of your traffic, ad blockers, and a tag that fires before the order data is available. A steady percentage gap points at the first; a drop on a specific date points at a change.
Does Shopify's native Google channel fix this?
The Google and YouTube channel app installs its own GA4 and Google Ads tracking through Shopify's pixel system and does cover express checkouts. The catch is running it alongside a GTM-based setup, which produces exactly the double counting described above. Pick one source for the purchase event.
Is a 10 to 15 percent gap between GA4 and Shopify normal?
A few percent is normal and comes from consent refusals, ad blockers and refund timing. Above that, especially if the gap is stable, look for an untracked checkout path first.
Run the free audit at tageasy.io/check on your store: it checks whether the purchase tag carries revenue, and whether tracking survives past the homepage.