You opened two tabs this morning. GA4 says you did £18,200 last week. Shopify says £21,400. One of them looks like it is lying to you, and you have a budget call to make before lunch that depends on which number you trust.
Here is the uncomfortable part. Neither number is wrong. They disagree because they were built to measure different things, and most teams respond by building a reconciliation spreadsheet to paper over the gap every month. That is the wrong instinct.
The gap is not noise to be smoothed away. It is a signal. Once you know which direction it runs and whether it holds steady, the discrepancy in front of you tells you exactly what is broken and what to fix.
This piece shows you how to read that signal, in both directions, and the four-step method we run on every audit to reconcile the two for good.
PART 01Why they were never built to match¶
Think of Shopify as a till and GA4 as a security camera pointed at the door.
Shopify is your system of record for money. It logs revenue from completed, paid orders at the moment payment is captured, and it does this on its own servers. Nothing a customer's browser does can stop Shopify from recording a sale it has already taken payment for. When Ruler Analytics and others describe Shopify as the authoritative source for revenue and order counts, this is why.
GA4 is something else entirely. It is a behaviour tracker. It records a purchase event that fires in the customer's browser during a session, and that event only counts if the tag actually fires and reaches Google. So the question is not which platform is correct. The question is what each one is good at, and where the two inevitably part company.
PART 02What each one actually measures¶
The clearest way to see the gap is to follow a single order through both systems.
A customer checks out. Payment is captured. Shopify records the order immediately, server-side, and it stays recorded. On the same screen, the thank-you page loads and is supposed to fire a GA4 purchase event. If that event fires cleanly, both systems now agree on this one sale.
But plenty can go wrong in that half-second. The customer's connection drops before the tag fires. They close the tab the instant the order confirms. An ad blocker stops the script loading at all. In every one of those cases, Shopify still has the sale and GA4 never hears about it.
That single mismatch — multiplied across thousands of orders — is the whole story. One platform counts confirmed money. The other counts browser events that may or may not arrive.
PART 03Read the gap, don't just close it¶
Most articles on this topic hand you a list of causes and leave you to guess which one is yours. That is backwards. Before you touch a setting, characterise your gap on two axes: which direction it runs, and whether it is stable or jumpy. Those two answers route you straight to the cause.
PART 04When GA4 is lower than Shopify¶
This is the common case, and it is almost always an under-capture problem. The sale happened, Shopify banked it, and GA4 simply missed the event. The usual culprits, in order of how often we see them:
- The purchase event never fired. Ad blockers and privacy browsers stop the GA4 script loading. In the UK and EEA, a customer who declines your consent banner cannot legally be tracked, so a real sale is recorded by Shopify and invisible to GA4. Slow connections and tabs closed too quickly do the rest. This is the heart of GA4 ecommerce tracking not working, and it is why client-side tracking always leaks.
- The native integration only sends the subtotal. If you are using Shopify's built-in GA4 connection, the purchase revenue it reports is the subtotal — it excludes tax and shipping. Compared against Shopify's gross figure, GA4 will always look smaller, even when every event fires.
- A broken tag in the checkout flow. A theme update, an app conflict, or a change to the thank-you page can quietly stop the event. This version of the problem shows up as a sudden drop rather than a steady gap.
PART 05When GA4 is higher than Shopify¶
This direction is rarer, quieter, and far more dangerous — because GA4 over-reporting flatters every downstream number you rely on. Your ROAS looks better than it is. Your ad spend looks more efficient than it is. Your forecasts are built on revenue that was never really there.
- Duplicate purchase events. A customer refreshes the thank-you page, or you have both the native integration and a GTM tag firing, and the same order is counted twice. GA4 deduplicates by
transaction_idwithin a 24-hour window — but only if a stabletransaction_idis actually being sent, and counts can still inflate temporarily. - No refund tracking. This is the big one. Shopify's native pixel cannot fire a refund event, because refunds happen in the admin or via the API — not in a customer's browser. Without a server-side refund event, GA4 keeps the original purchase revenue forever, even after you have refunded the order. Refund a £500 return and GA4 still shows £500 in revenue and one conversion, indefinitely.
- Revenue sent with tax and shipping included. A custom GTM + GA4 + Shopify setup may pass
valueincluding tax and shipping while you compare it to Shopify's net figure. If GA4 is consistently higher by roughly your average tax rate, this is the cause. - Currency misconfiguration. GA4 does not convert currency. Shopify converts at transaction time on a live rate and reports in your base currency, while GA4 records whatever currency code the event passes. On multi-currency stores this produces an irregular gap that tracks the exchange rate rather than a clean multiplier.
PART 06Stable gap vs variable gap¶
The second axis is just as diagnostic as the first.
A gap that sits at roughly the same percentage every week is structural. Currency handling, tax and shipping inclusion, timezone offset, a consistent consent-decline rate — these are annoying but predictable, and you can reconcile them with a known adjustment. A stable gap rarely needs urgent attention.
A gap that swings week to week is a live tracking error. A tag that fires intermittently, a consent banner that changed, duplicate events that come and go, an app that broke. This is the gap that needs fixing, not reconciling, and the sooner the better, because every week it moves is a week your reports cannot be trusted.
PART 07Capture is not attribution¶
Here is the distinction that separates teams who fix this from teams who chase their tails for months.
The total gap between GA4 and Shopify revenue is a capture problem. Did the event fire, and did it carry the right value and currency? That is it.
How GA4 then divides that revenue across Google, Meta, email, and direct is a completely separate attribution problem, governed by GA4's attribution model and lookback window. GA4's default reporting model has been data-driven attribution since 2020, and the older first-click, linear, time-decay and position-based models were removed in November 2023.
The trap is obvious once you name it. Teams see a revenue gap, assume attribution is wrong, and start changing attribution settings. The attribution model only moves revenue between channels. It does not change your total.
If your total is off, the problem is capture — not attribution — and no amount of model-switching will close it. Need to self-diagnose before going further? The free E-commerce Data Audit Checklist walks you through the firing checks step by step.
PART 08The reconciliation method we run on every audit¶
Once you can read the gap, reconciling it is a repeatable four-step process. This is the same sequence we use at the start of every audit.
Step 1 · Pull both sources for the same window
Open GA4, go to Explore, and build an Ecommerce purchases report. Open Shopify Analytics and pull the Finances summary. Set both to the same date range — and verify the timezone genuinely matches. Timezone misalignment is the silent killer here: a 30-day comparison can look broken purely because the two systems disagree about when each day starts and ends.
Step 2 · Establish direction and stability
Calculate the gap as a percentage, then characterise it using the two axes above. Is GA4 higher or lower than Shopify? Is the gap roughly stable across several weeks, or does it swing? Write the answer down before you do anything else — it tells you which family of causes you are dealing with and stops you fixing the wrong thing.
Step 3 · Find the unmatched orders with SQL
If you have both datasets in a warehouse — a GA4 BigQuery export alongside a Shopify export — you can find the exact orders causing the gap rather than guessing.
This query finds purchases GA4 recorded that Shopify never confirmed (over-capture candidates):
-- Orders GA4 recorded that Shopify never confirmed
SELECT transaction_id
FROM ga4_events
WHERE event_name = 'purchase'
AND transaction_id NOT IN (
SELECT order_id FROM shopify_orders
);
And this one finds the mirror image — orders Shopify confirmed that never reached GA4 (under-capture candidates):
-- Orders Shopify confirmed that never reached GA4
SELECT order_id
FROM shopify_orders
WHERE order_id NOT IN (
SELECT transaction_id
FROM ga4_events
WHERE event_name = 'purchase'
);
If you do not have a warehouse yet, that is fine. The point is that the gap is made of specific, findable orders — not abstract data loss — and naming them is the first step to fixing the cause behind them.
Step 4 · Fix the source, not the report
This is where most teams go wrong. They find the gap and respond by building a better spreadsheet to reconcile it every month. Stop. Fix the source instead.
- Correct the event firing so fewer purchases leak.
- Send refund events server-side using Shopify's refunds webhook so refunded revenue actually leaves GA4.
- Send
valueandcurrencycorrectly so the figures are comparable. - Align your timezone in GA4's data stream settings.
The goal is one trustworthy source of truth — not two numbers you reconcile by hand forever.
PART 09What a clean implementation looks like¶
You cannot judge your gap without knowing what good looks like. Here is the benchmark.
A complete e-commerce GA4 + Shopify setup fires seven events across the customer journey: view_item, add_to_cart, begin_checkout, add_payment_info, purchase, refund, and view_item_list. The purchase event must carry a transaction_id for deduplication, a numeric value, a valid ISO 4217 currency code (GBP, USD, EUR), and a populated items array. Miss any of those and you get events that fire but report zero revenue, or revenue with no product detail.
transaction_id matches the Shopify order number. Then compare GA4 purchase counts to Shopify orders for the same seven days.
Now the number that matters — and the one most articles get wrong. A clean client-side build does not match Shopify exactly, and it never will. Expect to land within roughly 5–10% of Shopify, which Ruler Analytics treats as normal, and others put as high as 10–12%. EEA and B2B audiences run wider because of higher consent-decline and ad-blocker rates. Server-side tagging narrows the gap toward low single digits.
A zero gap is not a realistic target, and anyone promising it is selling something. If your gap is well above 15–20%, you have a configuration error, not normal variance.
PART 10When to stop reconciling and fix the plumbing¶
A reconciliation spreadsheet that has existed for more than two months is a symptom, not a solution. Every month you keep it, someone on your team spends hours aligning two numbers that should never need aligning, and you make decisions inside the uncertainty in between.
The underlying fix, in most cases, takes a few days. The spreadsheet costs you those hours every month, forever, and it never actually tells you which orders are missing or why. At some point the maths stops favouring the workaround.
If your gap is variable, or it stays wide after you have worked through the four steps, the cause is in your tracking layer — and that is exactly what we find in the first hour of an audit. The full data audit framework covers the 40 checkpoints we run across every layer.
Download the free checklist
The E-commerce Data Audit Checklist walks through the firing checks in this piece, step by step. Three pages, free, no email gate.
→ Get the checklistBook a 20-minute audit call
We will walk through your actual GA4 and Shopify numbers together. If the cause is obvious, we will tell you on the call. No pitch if it does not apply.
→ Book a callPART 11Frequently asked questions¶
Why don't GA4 and Shopify match?
Because they measure different things at different moments. Shopify records paid orders server-side at payment capture, while GA4 records a browser event that only counts if it fires and reaches Google. Some events always leak, so the two never line up exactly.
How big a gap between GA4 and Shopify is normal?
A clean client-side setup typically lands within 5–10% of Shopify, sometimes a little more for EEA or B2B audiences. A gap consistently above 15–20% usually points to a configuration error rather than normal variance.
Why is my GA4 revenue higher than Shopify?
Almost always duplicate purchase events from thank-you page refreshes or double tags, or untracked refunds. Shopify cannot fire a refund event natively, so without a server-side fix, refunded revenue stays in GA4 indefinitely.
How do I fix a GA4 Shopify discrepancy?
Establish the direction and stability of the gap, find the unmatched orders, then fix the source rather than the report: correct event firing, send refund events server-side, and send the right value and currency. Reconciling by spreadsheet is a workaround, not a fix.
Sources. Ruler Analytics, GA4 and Shopify revenue discrepancy benchmarks; Google Analytics documentation on data-driven attribution (default from 2020, legacy models removed November 2023); Privado.ai State of Website Privacy Report 2024; author's field notes from e-commerce data audits 2023–2026.
