TL;DR
Shopify Analytics reports revenue from completed orders at the moment payment is captured. GA4 reports revenue from sessions where a purchase event was recorded, which depends on whether the browser pixel fired or a server-side hit arrived. These are two fundamentally different measurements. The gap between them is not a bug. It is the sum of six structural differences that every store has, and each one can be quantified and accounted for.
Key Takeaways
- Shopify counts revenue at payment capture; GA4 counts revenue when a
purchaseevent fires in a session. These are different moments for different entities. - GA4's data-driven attribution (default since November 2023) distributes fractional credit across touchpoints, so a single $100 order might show up as $40 on one campaign and $60 on another.
- Timezone mismatches between your Shopify store and GA4 property shift orders across date boundaries, creating daily discrepancies that cancel out over longer windows.
- If your store sells in multiple currencies, Shopify reports in your store's base currency while GA4 records whatever currency the
purchaseevent passes, with no automatic conversion. - Without server-side refund tracking, GA4 overstates revenue permanently because refunded purchases stay as counted conversions.
- Shopify includes all captured orders regardless of source (admin, POS, draft orders, API). GA4 only knows about orders that triggered a purchase event through a browser pixel or server-side hit.
Why do Shopify and GA4 show different revenue?
They are measuring different things.
Shopify Analytics records revenue when payment is captured on an order. Every order gets counted: online checkout, POS terminal, draft order, subscription renewal, bulk import. If money moved, Shopify logged it.
GA4 records revenue when a purchase event arrives, either from a browser pixel firing on the thank-you page or from a Measurement Protocol hit sent server-side. If no event fired, GA4 has no idea the order happened.
These are not two views of the same data. They are two separate systems with different triggers, different clocks, and different rules for what counts. The gap is structural and permanent. The goal is not to make the numbers match. The goal is to understand why they differ and verify that the delta is explainable.
Six specific causes account for nearly all of the discrepancy.
Reason 1: Attribution windows
Often the largest single contributor to the gap, especially when comparing Shopify revenue to GA4 campaign-attributed revenue.
Shopify does not attribute orders to marketing campaigns. When you pull revenue from Shopify Analytics, you get the total. No fractional credit, no attribution model, no lookback window.
GA4 uses data-driven attribution by default (switched from last-click in November 2023). It distributes conversion credit across multiple touchpoints. A single $100 order might show as $40 on a Google Ads click from three days ago, $35 on an organic visit yesterday, and $25 on a direct visit today.
The problem compounds across platforms. Meta uses a 7-day click / 1-day view attribution window by default. Google Ads uses a 30-day click window. TikTok uses a 28-day click / 1-day view window. Each platform claims credit for the same order under its own rules, which is why summing Meta + Google Ads + TikTok attributed revenue almost always exceeds Shopify's total.
The fix is not to change the windows. Use each platform's attributed revenue for within-platform optimization decisions, and use Shopify as the source of truth for actual collected revenue.
Reason 2: Counting method (orders vs sessions)
Shopify counts orders. GA4 counts sessions with purchase events.
This distinction matters in three specific scenarios:
Scenario 1: The purchase event never fires. A customer completes checkout, but an ad blocker, ITP, or a script error blocks the browser pixel. Shopify records the order. GA4 does not. Server-side tracking reduces this gap because the event is sent from your server regardless of browser conditions (see the server-side section below).
Scenario 2: The purchase event fires twice. Both a browser pixel and a server-side hit fire for the same order without proper deduplication (matching transaction_id values). GA4 records the order twice. Shopify still shows one. Consistent transaction_id across both layers prevents this.
Scenario 3: Admin, POS, and API orders. Orders created in Shopify admin, at a POS terminal, through draft orders, or via API (subscription renewals, wholesale, ERP imports) all count in Shopify revenue. None trigger a browser-side purchase event. Without server-side tracking for non-storefront orders, these are invisible to GA4. The admin and POS tracking guide covers this in detail.
The directional effect: Reason 2 almost always pushes GA4 revenue below Shopify revenue. The rare exception (duplicate firing) pushes GA4 above, but that is a configuration error rather than a structural cause.
Reason 3: Timezone mismatches
Your Shopify store and GA4 property each have their own timezone setting. If they differ, orders near midnight get assigned to different dates in each system.
Example: a customer checks out at 11:45 PM Eastern on June 14. A Shopify store set to Eastern time records it on June 14. A GA4 property set to UTC records it on June 15 (11:45 PM Eastern = 3:45 AM UTC).
The daily discrepancy is real but self-correcting: it cancels out over any window longer than one day. Weekly and monthly totals are unaffected except at the edges.
How to check: Shopify Admin > Settings > General for your store timezone. GA4 Admin > Property Settings for the reporting timezone. If they differ, align them. If you cannot (corporate timezone requirements), compare weekly or monthly instead of daily.
Reason 4: Currency and exchange rates
If your store sells in a single currency and your GA4 property uses the same currency, skip this section.
For multi-currency stores, Shopify converts all revenue to your store's base currency using Shopify Payments' exchange rate at capture time. That rate is fixed once the order is recorded.
GA4 records whatever currency the purchase event passes in the currency parameter. If the tracking sends the presentment currency (what the customer paid in), GA4 shows revenue in a mix of currencies. GA4's own currency conversion uses a different exchange rate source and may apply it at a different time.
WeltPixel Conversion Tracking passes order.currency directly to GA4 without conversion, which means GA4 receives the actual currency of the transaction. This is the correct behavior for GA4 reporting accuracy (GA4 expects the currency the customer transacted in), but it means the raw numbers in GA4 are in presentment currency while Shopify's totals are in base currency. Any comparison needs to account for that.
How to check: In GA4, go to Reports > Monetization > Ecommerce purchases and add "Currency" as a secondary dimension. If you see multiple currencies, your multi-currency setup is contributing to the gap. Compare per-currency totals rather than aggregates.
Reason 5: Refund handling
This is the most common source of GA4 overstating revenue relative to Shopify.
Shopify deducts refunds from revenue reports automatically. When you refund an order in Shopify admin, the gross revenue figure in Shopify Analytics drops by the refund amount. Net revenue reflects reality.
GA4 does not know about refunds unless something explicitly sends a refund event with a matching transaction_id. Without that event, the original purchase stays in GA4's data permanently. Revenue stays inflated. ROAS calculations run on numbers that are higher than reality by your refund rate.
The problem is architectural. Shopify's Web Pixels API has no refund event type because refunds happen in the admin, not in a customer's browser. There is nothing for a pixel to fire on. The only path to GA4 refund tracking on Shopify is server-side, via the refunds/create webhook. The refund tracking deep dive covers the full mechanism.
WeltPixel Conversion Tracking on the Plus plan ($39/mo) fires GA4 refund events via the refunds/create webhook with matching transaction_id values. Without this or an equivalent server-side solution, the gap between Shopify's net revenue and GA4's reported revenue grows by your refund volume every month.
How to quantify: Pull Shopify's total refunds for any month (Reports > Sales > Filter by refunds). That number is approximately how much GA4 is overstating revenue for that month, assuming no other refund-tracking mechanism is in place.
Reason 6: Order status filtering
Shopify Analytics lets you filter by order status: paid, partially paid, refunded, voided, pending. The default view in most Shopify reports shows paid orders.
GA4 has no concept of order status. A purchase event fires at checkout completion, and that event is final. If an order is later voided, cancelled before fulfillment, or flagged as fraudulent, Shopify can exclude it from reports. GA4 cannot, unless a refund event is explicitly sent.
This creates a specific gap for three order types:
- Cancelled orders that were never fulfilled. Shopify excludes them from net revenue. GA4 counted them at checkout.
- Fraudulent orders caught by Shopify's fraud analysis after checkout. Shopify can void them. GA4 already recorded the purchase event.
- Pending payment orders (common with manual payment methods, bank transfers, COD). Shopify may not count these as revenue until payment is confirmed. GA4 counted the purchase event at checkout submission.
The directional effect is the same as Reason 5: GA4 overstates relative to Shopify because GA4 has no mechanism to retract a purchase event other than a matching refund event.
How does server-side tracking affect the gap?
Server-side tracking reduces one specific component of the gap (Reason 2: lost browser events) but does not eliminate the structural divergence.
What it fixes: when an ad blocker or ITP blocks the browser pixel, a server-side hit still delivers the purchase event to GA4 via the Measurement Protocol. WeltPixel Conversion Tracking also sends campaign_details events server-side before the purchase event so GA4 has clean session attribution. The order is not just counted but correctly attributed to its traffic source.
What it does not fix: attribution windows (Reason 1), timezone mismatches (Reason 3), currency handling (Reason 4), refund tracking (Reason 5), and order status filtering (Reason 6). These are structural differences between the two systems, not tracking gaps.
Stores that add server-side tracking typically see GA4 revenue move closer to Shopify revenue because the biggest source of under-reporting gets closed. The remaining five differences mean the numbers will still diverge, but the gap becomes smaller and easier to reconcile. The GA4 setup guide covers the full browser + server-side setup.
Revenue reconciliation checklist
Use this checklist monthly to quantify each component of the gap between Shopify and GA4.
Step 1: Align the comparison window. Confirm your Shopify store timezone and GA4 property timezone. If they differ, compare weekly or monthly totals (not daily) to neutralize the midnight-boundary shift.
Step 2: Pull Shopify gross revenue. Shopify Admin > Analytics > Reports > Sales over time. Use "Gross sales" for the period. Note the currency.
Step 3: Pull GA4 purchase revenue. GA4 > Reports > Monetization > Ecommerce purchases. Use the "Purchase revenue" metric for the same period. Note the currency. If multi-currency, add "Currency" as a secondary dimension.
Step 4: Calculate the raw delta. Subtract GA4 revenue from Shopify revenue. A positive number means Shopify is higher (most common). A negative number means GA4 is higher (less common, usually indicates duplicate firing).
Step 5: Account for refunds. Pull Shopify's total refund amount for the period. If you do not have server-side refund tracking, add this to the expected delta (GA4 overstates by this amount).
Step 6: Account for non-storefront orders. Pull orders created via admin, POS, draft orders, and API for the period. Sum their revenue. If these are not tracked server-side, subtract this from Shopify's total before comparing (these orders are invisible to GA4).
Step 7: Account for lost browser events.
Compare the count of GA4 purchase events to Shopify's total order count (excluding non-storefront orders from Step 6). The difference approximates orders where the browser event was lost. Multiply by average order value for the revenue impact.
Step 8: Evaluate the residual.
After Steps 5-7, the remaining delta should be small (attribution-model differences + currency variance). If it is large and unexplained, investigate whether purchase events are double-firing (check transaction_id deduplication) or whether a tracking configuration changed mid-period.
FAQ
What is an acceptable gap between Shopify and GA4 revenue?
There is no universal threshold, but stores with properly configured server-side tracking and refund event firing typically see GA4 within 5-15% of Shopify's net revenue. The gap widens with higher refund rates, more non-storefront orders (admin, POS, API), and multi-currency sales.
Should I trust Shopify or GA4 for revenue reporting?
Shopify is the source of truth for actual collected revenue. It records every order regardless of how the customer arrived or whether a pixel fired. Use Shopify for financial reporting, inventory planning, and any context where you need the real number. Use GA4 for understanding which channels, campaigns, and landing pages drive conversions, and for optimizing marketing spend. They answer different questions.
Does Google Ads show the same revenue as GA4?
Not necessarily. Google Ads uses its own attribution model and window (30-day click by default), and only counts conversions linked to ad interactions. GA4 counts all sessions with purchase events regardless of source. Comparing the two is comparing two different attribution models. The Enhanced Conversions guide covers how Google Ads attribution works on Shopify.
Can I make Shopify and GA4 show exactly the same number?
No. The six structural differences described above are inherent to how the two systems work. You can minimize the gap (server-side tracking, refund events, timezone alignment, single currency), but a residual difference will always remain due to attribution model differences and the fundamental distinction between order-based and session-based measurement. The goal is a predictable, explainable delta, not zero.
How does Meta's reported revenue compare to Shopify and GA4?
Meta uses its own attribution window (7-day click / 1-day view by default) and matching logic (Advanced Matching via hashed customer data). Meta's reported purchase value often exceeds both Shopify and GA4 because view-through attribution counts conversions where the user saw an ad but converted from a different source. This is expected behavior, not a tracking error. The Meta Event Match Quality guide explains how Meta's matching works.
WeltPixel Conversion Tracking ensures your purchase events reach GA4, Meta, TikTok, Google Ads, and Reddit server-side with consistent transaction_id and event_id, which reduces under-reporting. Install WeltPixel Conversion Tracking.