If you run a Shopify store with GA4 tracking, you’ve almost certainly noticed that GA4 revenue and Shopify revenue don’t match. Not by a few pounds — often by 15–30% or more.
This causes legitimate concern. If GA4 is underreporting revenue, how do you trust your attribution data? How do you know which campaigns are actually profitable?
The reassuring truth: a discrepancy of 5–15% is normal and expected. A discrepancy of 20–40% indicates a tracking problem worth fixing. This guide explains every root cause and what to do about each one.
Why Discrepancy Is Always Expected
Before diagnosing problems, understand that GA4 and Shopify are fundamentally measuring different things:
Shopify records: Every completed transaction, regardless of how the user got there. It records refunds, cancelled orders, and test orders. It uses server-side data — every order gets logged regardless of whether the customer’s browser sent a tracking event.
GA4 records: Purchase events sent from the user’s browser (or a server-side implementation). It depends on JavaScript executing successfully, cookies being accepted, network requests completing, and the user not having an ad blocker.
These are structurally different measurement approaches. Perfect agreement is not achievable. The goal is to understand the gap and keep it within an acceptable range.
The 10 Causes of GA4-Shopify Revenue Gaps
Cause 1: Ad Blockers and Privacy Extensions
Ad blockers like uBlock Origin, Privacy Badger, and iOS content blockers intercept requests to google-analytics.com. When a user with an ad blocker completes a purchase, Shopify records the order — but the GA4 purchase event never fires.
Estimated impact: 10–25% of users have some form of ad blocking. In B2B or tech-focused audiences, this can reach 40%.
Fix: Implement server-side purchase tracking using GA4’s Measurement Protocol. When Shopify’s orders/paid webhook fires, your server sends the purchase event to GA4 directly — bypassing the browser and any blockers.
# Example: Shopify webhook → Measurement Protocol
import requests
def send_ga4_purchase(order):
payload = {
"client_id": get_client_id_from_order(order), # from _ga cookie stored at checkout
"events": [{
"name": "purchase",
"params": {
"transaction_id": order["name"], # e.g., "#1234"
"value": float(order["total_price"]),
"currency": order["currency"],
"items": [...]
}
}]
}
requests.post(
f"https://www.google-analytics.com/mp/collect?measurement_id=G-XXXXXXXX&api_secret=XXXXXXXX",
json=payload
)
This is the most impactful fix available.
Cause 2: Shopify’s Checkout Redirect Chain
Shopify’s checkout lives on a different domain (checkout.shopify.com for most stores, or checkout.yourstore.com for Plus stores with custom domains). This cross-domain redirect breaks the GA4 session.
When a customer:
- Browses your Shopify store (tracked in GA4 session)
- Clicks “Buy” → redirected to
checkout.shopify.com - Completes purchase → redirected back to order confirmation
GA4 sees this as a new session when the user lands on the thank-you page. The session source/medium is often reset to (direct) / (none), breaking attribution. Worse, if the GA4 client ID isn’t preserved across the redirect, the purchase event can appear under a different user.
Fix: Enable cross-domain tracking in GA4 for the checkout domain.
In GTM → GA4 Configuration tag → Fields to Set:
- Field:
linker - Value:
{"domains": ["checkout.shopify.com", "yourstorename.myshopify.com"]}
Or in the GA4 tag’s Cross-Domain Measurement settings, add both your store domain and the checkout domain.
For Shopify Plus stores with custom checkout domains, add your specific checkout subdomain.
Reference: GA4 cross-domain measurement setup
Cause 3: Thank-You Page Tracking After Shopify’s August 2025 Migration
Before Shopify’s checkout extensibility migration, most stores tracked purchases using a custom pixel or code injected via checkout.liquid on the thank-you page. Post-August 2025, the thank-you page and order status page are handled by Shopify’s new Checkout Extensibility system.
Stores that didn’t migrate their tracking properly saw GA4 purchase events drop to near zero after the migration deadline.
Symptoms: Your GA4 purchase count dropped sharply in August-September 2025.
Fix: Set up GA4 tracking via Shopify’s Customer Events (Web Pixels API):
- Shopify Admin → Settings → Customer events → Add custom pixel
- Add a custom pixel with:
analytics.subscribe('checkout_completed', (event) => {
const checkout = event.data.checkout;
gtag('event', 'purchase', {
transaction_id: checkout.order.id,
value: parseFloat(checkout.totalPrice.amount),
currency: checkout.currencyCode,
tax: parseFloat(checkout.totalTax?.amount || 0),
shipping: parseFloat(checkout.shippingLine?.price?.amount || 0),
items: checkout.lineItems.map((item, index) => ({
item_id: item.variant?.sku || item.variant?.id,
item_name: item.title,
item_variant: item.variant?.title,
price: parseFloat(item.variant?.price?.amount || 0),
quantity: item.quantity,
index: index
}))
});
});
Cause 4: Refunds and Cancellations
Shopify’s revenue figures in your Shopify admin include refunds as negative revenue when you run reports for a period. GA4, by default, records the purchase at the time of the order — it does not automatically deduct refunds unless you send a refund event.
If your return rate is 10% and you’re comparing last month’s GA4 revenue to last month’s Shopify net revenue, Shopify will show lower revenue (net of refunds) while GA4 shows gross.
Fix: Compare gross revenue figures (before refunds) in both systems. Alternatively, implement GA4 refund events using the Measurement Protocol when Shopify’s refunds/create webhook fires.
Cause 5: Test Orders and Draft Orders
If your team places test orders through Shopify, they appear in Shopify’s revenue data. GA4 may or may not capture them depending on whether you have analytics running in your development/staging environment.
Fix: Exclude internal IP addresses and staff accounts from both Shopify reports and GA4. In GA4 → Admin → Data Filters → create an “Internal Traffic” filter and exclude your office IP.
In Shopify, exclude staff accounts when running sales reports by filtering by customer type.
Cause 6: Payment Method Redirects (PayPal, Klarna, Afterpay)
Some payment methods redirect users to an external site to complete payment (PayPal being the most common). When the user is redirected to PayPal and then back to your store, GA4 again encounters a cross-domain issue. The return URL often contains a ?utm_nooverride parameter or doesn’t preserve the GA client ID.
This means:
- The session source gets reset to
paypal.com / referral - The original campaign attribution is lost
- The purchase event may appear under a different session than the one that started checkout
Fix:
- Enable cross-domain tracking to include
paypal.comin your linker configuration (prevents PayPal from appearing as a referral) - Add PayPal to your GA4 referral exclusions list: Admin → Data Streams → Configure Tag Settings → List Unwanted Referrals
Cause 7: Browser Privacy (Safari ITP, Firefox ETP)
Safari’s Intelligent Tracking Prevention and Firefox’s Enhanced Tracking Protection actively limit tracking cookies. Specifically:
- JavaScript-set
_gacookies are capped at 7 days in Safari (down from 2 years) - Cookies from third-party scripts may be blocked entirely
If a Safari user browses your store on Monday, leaves without buying, returns on day 8, and purchases — GA4 sees them as a new user rather than a returning one. The session and attribution from day 1 are lost.
Impact on revenue discrepancy: Directly smaller — this affects attribution more than whether the purchase is recorded at all. But in stores with long purchase cycles, Safari ITP can significantly distort your attribution data.
Fix: Server-side tracking (as mentioned in Cause 1) sets the _ga cookie via HTTP headers from your server, which isn’t subject to ITP’s JavaScript restrictions. This extends the attribution window for Safari users.
Cause 8: Network Failures and Script Load Errors
GA4’s JavaScript must load, execute, and successfully send a network request to google-analytics.com before the user leaves the thank-you page. On slow connections:
- The page loads
- The user quickly clicks away
- The GA4 script hasn’t finished loading
- The purchase event is never sent
Estimated impact: Low (1–3%) but real.
Fix: Server-side purchase tracking (Measurement Protocol) eliminates browser dependency entirely. Also ensure your GA4 script loads early in the page head, not deferred.
Cause 9: Shopify’s “Additional Scripts” Deprecation
Many older Shopify stores had GA4 or Universal Analytics code injected in Settings → Checkout → Additional Scripts. This section was deprecated as part of Shopify’s checkout extensibility migration. If your tracking code was there and wasn’t migrated, it’s simply gone.
Check: Go to Shopify Admin → Settings → Checkout → scroll to “Order status page”. If you see old GA tracking code there, it may no longer fire properly.
Fix: Migrate to the Web Pixels API (Customer Events) as described in Cause 3.
Cause 10: Currency and Tax Differences
Shopify can report revenue inclusive or exclusive of tax. GA4 records whatever value your purchase event sends. If your Shopify report shows revenue inclusive of VAT but your GA4 purchase event sends the pre-tax amount, you’ll see a systematic gap proportional to your tax rate.
Fix: Ensure your purchase event’s value matches whatever Shopify’s revenue reports use. Document your decision (tax-inclusive vs. exclusive) and apply it consistently.
Acceptable vs. Problematic Discrepancy Ranges
| Revenue Discrepancy | Assessment |
|---|---|
| 0–5% | Excellent — expected rounding and minor attribution variance |
| 5–15% | Good — normal given ad blockers and cross-domain sessions |
| 15–25% | Investigate — likely one major tracking issue (broken pixel, redirect problem) |
| 25–40% | Serious problem — likely multiple issues or broken thank-you page tracking |
| 40%+ | Critical — GA4 data is not usable for business decisions |
How to Diagnose Your Specific Gap
Step 1: Check event volume
In GA4 → Reports → Events → filter by purchase. Do the event counts roughly match Shopify order counts? If events are half the order count, the problem is at the firing level.
Step 2: Check the thank-you page in real time
Place a test order and watch GA4 DebugView in real time. Does a purchase event appear within 30 seconds of completing the order?
Step 3: Check with an ad blocker Repeat the test with uBlock Origin installed. Does the purchase event appear in DebugView? If not, implement server-side tracking.
Step 4: Check cross-domain linking
After adding a product to your cart, inspect the checkout URL. Does it contain a _gl parameter? This is the cross-domain linker — its presence confirms cross-domain tracking is active.
Example: checkout.shopify.com/...?_gl=1*abcdef*...
Step 5: Compare raw numbers Export last month’s Shopify orders (gross revenue, before refunds) and compare to GA4 revenue for the same period. Calculate the exact percentage gap so you have a baseline to improve against.
The Realistic Goal
Complete parity between GA4 and Shopify is not achievable — there will always be some users who can’t be tracked due to ad blockers, network failures, or privacy settings. The goal is to:
- Understand your baseline gap
- Implement server-side tracking to recover the largest single source of loss (ad blockers)
- Fix cross-domain tracking to preserve attribution
- Keep your gap consistently below 15%
At Aumlytics, we audit GA4-Shopify discrepancies as part of our analytics setup service. We identify the specific causes in your store and implement fixes that bring your GA4 data back to a reliable baseline. Book a free consultation to understand what’s causing your gap.