Why GA4 revenue doesn't match Stripe or Shopify
By Devendra Variya, co-founder of Virling. Published 2026-11-01.
TL;DR: GA4 counts purchase events that a browser sends. Stripe and Shopify count money that actually moved. Anything that stops the event from being sent, or changes the amount after it was sent, opens a gap. Trust your payment provider for revenue, and use analytics only to say where each payment came from.
The eight causes, and how to check each
| Cause | How to check | Fix |
|---|---|---|
| The purchase event never fires | Count GA4 purchase events and successful payments for the same day. Hosted checkouts such as checkout.stripe.com return to your site only if the buyer waits for the redirect | Send the purchase from your server when the payment webhook arrives, not from the thank-you page |
| Ad blockers and declined consent | Compare purchases in GA4 with orders in the same hour; the gap stays even on days with no other issue | Server-side events reduce it. Some gap is normal |
| Subscription renewals | In Stripe, invoices with billing reason subscription_cycle. No visit happens, so the browser sends nothing | Send renewals from the server, or use a tool that reads payments |
| Refunds and disputes | Your provider subtracts refunds; GA4 keeps the purchase unless you send a refund event | Send a refund event with the same transaction_id |
| Currency | Purchase events without a currency parameter do not count toward revenue. GA4 also converts to your property currency at its own rate | Always send currency with value |
| Tax, shipping and discounts | Compare one order's value in GA4 with its total in Shopify or Stripe | Decide what value means and send the same thing every time |
| Time zones | Your GA4 property and your Stripe or Shopify account can use different time zones, so orders near midnight land on different days | Compare whole weeks or months, or set both to the same zone |
| Duplicate purchase events | GA4 higher than Stripe usually means the thank-you page fired twice, for example on reload | Send a unique transaction_id so GA4 can drop the duplicate |
When the total matches but the channel is wrong
A second problem hides inside the first. When a buyer leaves for checkout.stripe.com or a PayPal page and comes back, GA4 can start a new session with the payment page as the referrer. The sale then belongs to Stripe or PayPal instead of the ad or post that brought the buyer. Add those domains to GA4's list of unwanted referrals in the data stream's tag settings.
Long buying cycles cause the same drift: a buyer who first came from a post and paid two weeks later from a bookmark shows as Direct under a last-click view. See first-touch or last-touch attribution.
How to send Stripe purchases to GA4
- When you create the Checkout Session, put the visitor's GA4 client ID in
client_reference_idormetadata. - Listen for the
checkout.session.completedwebhook on your server. - Send a
purchaseevent to GA4 with the Measurement Protocol, using that client ID, the session ID astransaction_id, the amount asvalueand thecurrency. - Send a
refundevent with the sametransaction_idwhen Stripe reports a refund. - Add checkout.stripe.com to GA4's unwanted referrals so the return visit keeps its source.
That fixes the missing and duplicate purchases. It does not bring in renewals unless you also send them from invoice.paid.
Which number to trust
Use your payment provider for revenue, refunds and renewals, because it is the ledger. Use analytics for the question it can answer: which visit came before each payment. The reliable way to join the two is to pass a visitor ID into checkout and match each payment to that visitor's visits, as in tracking Stripe revenue by traffic source.
Virling does this join for you. It reads payments from Stripe, Shopify and seven other providers with a read-only key, so its revenue matches your provider, and credits each payment to the visit before it. Renewals keep the channel of the first payment.
Frequently asked questions
Why is GA4 revenue lower than Stripe?
Usually because purchase events never fire: buyers who close the tab after paying, blocked or declined tracking, and subscription renewals that happen without a visit. Missing currency parameters also drop revenue.
Why is GA4 revenue higher than Stripe or Shopify?
Duplicate purchase events, often from a reloaded thank-you page, and refunds that GA4 never hears about. Send a unique transaction_id and a refund event.
Does GA4 track Stripe subscription renewals?
Not on its own. A renewal is charged with no visit, so no browser event is sent. You have to send it from your server or use a tool that reads payments from Stripe.
How do I stop checkout.stripe.com showing as a referrer in GA4?
Add checkout.stripe.com, and any other payment domain you use, to the list of unwanted referrals in your GA4 data stream's tag settings.
How do I connect Stripe to GA4?
Pass the GA4 client ID into the Checkout Session, listen for the checkout.session.completed webhook, and send a purchase event with the Measurement Protocol. Add checkout.stripe.com to GA4's unwanted referrals.
Get revenue that matches your payment provider, split by channel: start a 14-day free trial at app.virling.com.