Open beta — completely free, no card required.
Diagnostics

GA4 vs Shopify: Why the Numbers Don't Match (and How to Reconcile Them)

GA4 says one revenue number, Shopify says another, and they're both right. Which direction the gap runs, what size is normal, and a like-for-like reconciliation that lands on the real tracking loss instead of chasing zero.

By Ivan Pika

A client sent me two screenshots last week with one question: "Which one do I send the investor?"

Shopify said $148,200 for the month. GA4 said $121,500. Same store, same dates, an 18% gap, and a board update due in the morning. He wanted to know which number was the real one.

Neither. They're both real. That's the part nobody tells you. Shopify and GA4 are not two measurements of the same thing that should agree — they're two instruments pointed at two different events, and forcing them to match is how you waste an afternoon. The question isn't which one is right. The question is which direction the gap runs and whether its size is normal. Answer those two and the mystery turns into a constant you can ignore.

Why they can't match, and shouldn't

Shopify counts an order the moment payment is captured. That happens on Shopify's servers. No browser, no JavaScript, no consent banner stands between the sale and the count — if money moved, Shopify saw it.

GA4 counts a purchase event that fires in the customer's browser after the thank-you page loads. Between the captured payment and that fired event sits a long list of things that can swallow it: an ad blocker, a declined consent banner, a closed tab, a flaky connection on the train, a payment redirect that broke the session. Ad blockers and privacy browsers run somewhere between 10% and 30% of traffic in 2026, and every one of those users is a sale Shopify records and GA4 may never hear about.

So the baseline expectation is simple: GA4 should come in a bit under Shopify, always, on revenue and on order count. A store with zero discrepancy doesn't have perfect tracking. It has a bug — usually GA4 double-counting, which we'll get to. The same "did the visitor leave or did the tag stop seeing them" split that governs a sudden traffic drop governs this too: Shopify is the server-side truth, GA4 is the browser-side estimate.

First fork: which direction is the gap?

Before you touch a single setting, look at the sign.

GA4 below Shopify is the normal world. Roughly four out of five stores live here. It means the browser ate some of your purchase events, which it always does, and the only question left is how much. A 10–20% shortfall is the cost of measuring in browsers. Inside that band, nothing is broken. You are looking at physics, not a misconfiguration.

GA4 above Shopify — over a properly matched window — is the abnormal world, and it's almost always a bug. Lost data doesn't find its way back and then some. If GA4 is reporting more revenue than the store actually took, something is inflating it: a double-firing tag, refunded orders that never got removed, tax and shipping bundled into the number. That's a different investigation with a different fix, and it's covered further down.

The word "matched" is doing real work in that paragraph. Day by day, a timezone offset between your Shopify store and your GA4 property will flip the sign back and forth as orders near midnight slide across the date boundary. Direction only means something over a full closed window where those edges cancel. Compare a whole calendar month, not yesterday.

The reconciliation, for the normal case (GA4 below Shopify)

Here's where almost every guide on this query goes wrong. They hand you an unordered pile of causes — timezone, currency, refunds, ad blockers, consent — and tell you to "implement server-side tracking." That's not a method. That's a word cloud.

The method is the opposite of a one-way subtraction, because the causes don't all push the same way. Tax and shipping baked into GA4's number push it up. Refunded orders that GA4 never removed push it up. Browser loss pushes it down. If you just start subtracting things from the gap, your math will never close and the whole exercise feels like guesswork.

So don't subtract from the gap. Align both sides to the same definition first, then read whatever is left. You're making Shopify and GA4 describe the exact same thing — same revenue components, same refund treatment, same currency, same window — and the residual that survives is your real tracking loss.

Four things to align, in the order that closes the gap fastest:

Revenue definition. Shopify's "Total sales" includes tax and shipping; its "Net sales" strips them but subtracts returns. GA4's purchase value includes whatever your tag passes — often product revenue only, sometimes with tax and shipping, depending on setup. Pick one definition and force both reports to it. This single mismatch routinely accounts for 10–15% of a "gap" that was never a gap.

Refunds. Shopify nets out returns. GA4 keeps the original purchase forever unless your store sends a refund event, which most don't. So Shopify's net number is smaller than GA4's on this axis. To compare honestly, line up GA4 against Shopify's gross (pre-return) revenue, or start sending refund events.

Timezone and window. A store set to America/New_York and a GA4 property left on America/Los_Angeles disagree by three hours, and every order near midnight lands on a different calendar day in each system. Over a month the misplaced orders roughly cancel, which is exactly why you reconcile on a full closed month and never on a single day.

Currency. If you sell in more than one currency, Shopify reports in your store's base currency while GA4 logs whatever number the purchase event passed. If the event sends local amounts without converting them, GA4 quietly inflates. Check the currency split — a clean setup converts everything to one currency before it hits GA4.

Once those four match on both sides, whatever's left is browser loss. If it's 10–20%, you're done. Stop reconciling and go do your job.

Notice attribution isn't on that list. It's the bucket every blog wants to add and it doesn't belong. GA4's total purchase revenue is the sum of every purchase event's value, recorded when the event fired — the attribution model only decides which channel gets credit for that revenue. It never changes the total. Attribution explains why Shopify and GA4 disagree about whether Google or email drove a sale. It explains nothing about the top-line number.

Worked example: turning an 18% panic into a 9% shrug

Back to the client with the investor update. Shopify $148,200, GA4 $121,500, headline gap 18%. We ran the alignment on a matched April, store timezone synced to the GA4 property.

Matched window: April 1–30, store timezone aligned to GA4

Shopify "Total sales"                              $148,200
  − tax + shipping  (GA4 value excludes them)      − $19,400   → $128,800
  + refunds         (GA4 has no refund events)     + $4,300    → $133,100
  currency          (checked — all converted USD)    $0        → $133,100

Shopify, matched to GA4's definition                            $133,100
GA4 purchase revenue                                            $121,500
─────────────────────────────────────────────────────────────────────────
Residual gap (browser / consent / redirect loss)                  8.7%
Normal band                                                       10–20%

The 18% headline was mostly definitional. His GA4 tag sent product revenue only, so the $19,400 of tax and shipping in Shopify's "Total sales" was never a discrepancy — it was two different line items. The $4,300 of refunds GA4 still carried because the store sends no refund events. Strip those, compare like for like, and the real tracking loss was 8.7%, sitting comfortably under the normal band.

Nothing was broken. He sent the investor the Shopify number — that's the money the company actually has — and stopped treating GA4 like a broken cash register. The 18% was never lost revenue. It was an accounting difference wearing a costume.

When GA4 is higher: the bug list

If GA4 out-totals Shopify over a matched window, you're not reconciling a measurement gap. You're hunting an inflation bug. Five suspects, in rough order of how often they're guilty.

A double-firing purchase event is the usual culprit. The event fires twice — a buyer refreshes the thank-you page, hits back and forward, or you have both a GTM tag and Shopify's native GA4 integration sending the same purchase. The tell is in the order count: pull GA4 transactions against Shopify orders for the month. One store I looked at showed 1,180 GA4 transactions against 790 real Shopify orders — 390 phantom sales, nearly all of them buyers reloading a confirmation page. Don't count on GA4 to clean this up after the fact. Unlike old Universal Analytics, it doesn't reliably de-duplicate purchases by transaction_id at reporting time, so the fix has to happen at the source: send the purchase event from one place and not two, guard against thank-you-page reloads, and give every order a stable transaction_id (the Shopify order ID) so any duplicates that slip through are at least identifiable in the data.

Tax and shipping in the value is the same definitional mismatch as before, running the other direction — GA4 includes them, the Shopify report you're eyeballing doesn't.

Refunded and cancelled orders inflate GA4 because, again, it never removes a purchase it already counted. If a chunk of the month's orders got cancelled and Shopify's view nets them out, GA4 keeps every one.

Test orders and internal traffic fire real purchase events if you're not filtering them — your own checkout tests, a staging order, a developer running the funnel.

Multi-currency inflation rounds out the list: unconverted local amounts logged as if they were base currency.

Every one of these is a configuration problem, not a tracking limitation. Find which one and the gap closes from the top.

The conversion-rate trap

"My Shopify conversion rate is 2.8% and GA4 says 3.4% — which is lying?" Neither. This one has two independent traps stacked on top of each other, and most people fall into both.

The first is the denominator, and it's the more common mistake. Shopify's conversion rate is session-based: converting sessions divided by total sessions. GA4 reports both a session-based key-event rate and a user-based one, and the user-based number is always higher because one person can open three sessions, so users are fewer than sessions and a smaller denominator lifts the rate. Take 10,000 sessions from 7,200 users with 300 orders: the session rate is 3.0%, the user rate is 4.2%, same store and same orders, just divided by two different things. If you put GA4's user rate next to Shopify's session rate, GA4 wins by a mile for a reason that has nothing to do with tracking. Match both to session-based before you compare anything.

The second trap is subtler, and it's why you can't just "correct" GA4's conversion rate using the revenue gap. The two tracking losses don't cancel cleanly. When GA4 misses a session that converted, it drops both the numerator and the denominator. When it misses a session that didn't convert, it drops only the denominator — which pushes GA4's conversion rate up. So whether GA4's conversion rate ends up above or below Shopify's depends on whether the traffic GA4 can't see converts better or worse than average. There's no fixed direction. The conversion-rate gap is its own number, and you cannot derive it from the revenue gap. Anyone telling you "GA4 undercounts purchases by 18%, so your true conversion rate is 18% higher" is doing arithmetic on two errors that don't combine like that.

If your conversion rate is falling over time inside GA4 rather than disagreeing with Shopify at a point in time, that's a different diagnostic entirely — see why your GA4 conversion rate dropped.

Which number owns which decision

Stop trying to merge them. Once you know your residual, give each system the job it's actually good at.

Shopify owns the dollar. Revenue, order count, average order value, refunds, taxes, what the business actually earned — that's the server-side truth, and it's what goes to finance, to the investor, to your P&L. Reporting GA4 revenue as company revenue is the cardinal sin here, and it happens constantly.

GA4 owns the journey. Which source and campaign and device and landing page produced those orders, where the funnel leaks, which channel's traffic converts and which just burns budget. Shopify's channel attribution is thin and roughly last-click; GA4 is the instrument built for "where did this come from and why." Asking Shopify which campaign drove conversions is the mirror-image mistake — using the dollar-of-record system to answer a behavioral question it was never built for. This is the same division of labor behind any real GA4 ecommerce analysis: GA4 for the path, Shopify for the receipt.

Reconcile once, learn your residual, then never reconcile again. Use Shopify for how much, use GA4 for how come.

Doing the GA4 side in one chat

The Shopify half of this is a CSV export and a definition you already understand. The GA4 half is where people lose an hour clicking through Monetization reports and Explorations to pull numbers that don't even live in one place.

Connect GA4 to an AI assistant — the no-code setup takes about five minutes — and the GA4 side of the reconciliation becomes a single prompt:

For last full month, show GA4 purchase revenue, transaction count, and AOV.
Break revenue down by currency and by session source / medium, and show the
daily purchase-revenue trend. Flag any day that looks like a double-count
spike or a timezone edge.

That returns exactly the pieces you carry over to your Shopify export: the revenue and order count to line up against Shopify's, the currency split that catches multi-currency inflation, the daily trend that exposes a timezone edge or a duplicate-firing spike. One honest limit — aggregated GA4 metrics can show you the symptom (1,180 transactions against 790 orders, or a Tuesday revenue spike that's double the trend) but not the config causing it. Whether tax is baked into value or whether the tag fires twice is something you confirm in GTM, Tag Assistant, or by comparing those counts to Shopify — not something any GA4 number reveals on its own. And the dollar of record never moves: Shopify stays the source for the money side, always.

That GA4-side forensics pass is what ConvRadar is built to make trivial. It plugs GA4 into Claude, ChatGPT, Cursor, or Perplexity and hands the assistant the read tools — revenue, AOV, currency and source breakdowns, daily trends — so the six explorations collapse into one question. It reads GA4 only; it doesn't touch Shopify, and it won't pretend to. The reconciliation is yours to run. The tool just removes the clicking.

FAQ

Why doesn't my GA4 revenue match Shopify? Because they measure different events. Shopify counts the order when payment is captured on its servers; GA4 counts a browser event that fires after the thank-you page loads. Ad blockers, declined consent, closed tabs, and broken payment redirects eat some of those browser events, so GA4 normally lands 10–20% below Shopify. Most of the rest of any gap is definitional — tax, shipping, and refunds counted differently on each side.

What's a normal discrepancy between GA4 and Shopify? GA4 running 10–20% below Shopify on revenue and orders is normal and expected, once you've matched the revenue definition (tax/shipping), refund treatment, timezone, and currency on both sides. Under 10% is excellent. Over 20% after aligning definitions points to a tracking or configuration problem worth chasing.

Why is my GA4 revenue higher than Shopify? Over a matched window, GA4 should never out-total Shopify, so a higher number is a bug. The usual cause is a purchase event that fires more than once — thank-you-page reloads, or both a GTM tag and the native integration sending it — and GA4 won't reliably de-duplicate it for you, so fix it at the source: one purchase tag, guard reloads, a stable transaction_id per order. Other causes: tax and shipping bundled into GA4's value, refunded or cancelled orders GA4 never removed, unfiltered test orders, and unconverted multi-currency amounts.

Why is my Shopify conversion rate different from GA4? First check the denominator. Shopify's conversion rate is session-based; GA4 reports both session-based and user-based rates, and the user-based one is always higher because users are fewer than sessions. Compare session-based to session-based. After that, the tracking gap remains, but it doesn't move the conversion rate in a fixed direction — missed non-converting sessions actually push GA4's rate up — so you can't predict the conversion-rate gap from the revenue gap.

Which should I trust, GA4 or Shopify? Both, for different things. Shopify is the truth for money: revenue, orders, AOV, refunds. That's what goes to finance. GA4 is the truth for behavior: which source, campaign, device, and page drove the orders and where the funnel leaks. Use Shopify for how much, GA4 for how come.

How do I make GA4 match Shopify exactly? You don't, and you shouldn't try. Browser-based measurement will always miss some server-side sales. The goal is a known, stable residual — align both sides to the same definition, confirm the leftover gap is in the 10–20% band, and treat that number as a constant rather than a problem to solve.

They were never two readings of the same number. Once you know your residual, the gap stops being a question and becomes a footnote — send the investor the Shopify figure, and ask GA4 where it came from.