GA4 Not Showing Revenue by Channel? Here's Why and How to Fix It
68% of SaaS teams see wrong or missing revenue-by-channel data in GA4. Here's why Stripe revenue never lands in your channel report and how to fix it.
Muzahid Maruf, Founder · TrackRev.io & Contant.io
On this page
Roughly 68% of B2B SaaS teams that connect Stripe to Google Analytics report that GA4 either shows no revenue by channel at all or shows numbers that contradict their Stripe dashboard by 20% or more.
You open the Traffic acquisition or User acquisition report expecting to see MRR split cleanly across Google, LinkedIn, newsletter, and affiliate, and instead you get a wall of 'Direct' and '(not set)', a revenue column that reads $0.00 for channels you know converted, or a total that is a third of what Stripe actually collected.
The instinct is to assume a broken tag. Usually the tag is fine. The problem is architectural: GA4 was built to measure e-commerce transactions that complete inside a single browser session, and SaaS revenue simply does not behave that way.
Every symptom in this article traces back to one root cause.
GA4 not showing revenue by channel is what happens when a browser-session analytics tool is asked to attribute revenue that is actually created server-side in your billing system, across multiple sessions, devices, and days it can never observe.
Key Takeaways
- GA4's Default Channel Grouping buckets 30-45% of paid SaaS revenue into 'Direct' or '(not set)' because subscription payments settle server-side in Stripe, outside any browser session GA4 can measure.
- GA4 only records revenue from a purchase event fired in the browser; recurring MRR, upgrades, and off-session renewals never fire that event, so they never appear in any channel row.
- Cross-domain hops to Stripe Checkout or a billing subdomain reset the GA4 session and reassign the conversion to 'Direct' unless you configure cross-domain measurement precisely.
- The 24-72 hour lag between a trial signup and the first paid charge routinely exceeds GA4's session window, breaking the link between the acquisition channel and the eventual revenue.
- A first-party attribution platform that reads Stripe as the source of truth ties every charge, renewal, and expansion back to the original UTM, which GA4's event model structurally cannot do.
Why This Matters for Your Revenue
When 30-45% of your paid revenue collapses into 'Direct', you are not just missing a report row. You are making budget decisions on inverted data.
The channel that GA4 credits with the most 'Direct' revenue is frequently the one you underfund, because 'Direct' looks like free demand nobody paid to create.
Meanwhile the paid channel that actually drove those signups shows a cost with no revenue beside it, so it gets cut in the next planning cycle.
Teams routinely kill their best-performing acquisition source because GA4 filed its revenue under a bucket that means 'we don't know'.
The money impact compounds because the mislabeled revenue is recurring. A misattributed $400/month subscription is not a $400 mistake, it is a $4,800 annual mistake, and every renewal reinforces the wrong conclusion.
If you spend $30,000 a month across four channels and GA4 hides which channel generates the LTV, your cost-per-acquisition math is fiction.
You cannot compute payback period, you cannot defend spend to a CFO, and you cannot tell whether a channel is profitable until months after you have already reallocated the budget away from it.
The core reason GA4 can't show your channel revenue
GA4 attributes revenue only when a purchase event fires inside a browser session it can see. SaaS revenue is created in Stripe: recurring renewals, off-session upgrades, and payments that settle 24-72 hours after the click never fire that browser event, so GA4 has no revenue to assign to any channel and defaults it to 'Direct' or '(not set)'.
The Six Reasons Revenue Never Reaches Your Channel Report
GA4's channel report fails for SaaS in six distinct, diagnosable ways. Most teams have three or four of them running at once, which is why the numbers look randomly wrong rather than wrong in a consistent direction.
Work through each one against your own setup before you blame the pixel.
1. The purchase event never fires for recurring revenue
GA4 can only credit revenue to a channel if a purchase event carries a monetary value into a session. The first checkout might fire that event.
The second month's renewal fires nothing, because no browser is involved when Stripe charges the saved card. Every renewal, every off-session upgrade, and every usage-based invoice is invisible to GA4 by design.
For a subscription business where 70-80% of annual revenue is renewal revenue, this alone means GA4 can never see the majority of the money, let alone attribute it to a channel.
This is the difference between tracking a signup and tracking revenue. If you want the channel that drives lifetime value rather than the channel that drove one browser transaction, GA4's event model is the wrong instrument.
We break this down further in our guide to crediting lifetime revenue, not just the first payment.
The tell: a spike in brand-search revenue
When renewal and multi-session revenue can't find their real source, GA4 disproportionately credits 'Organic Search' for your brand name, because that's what people type when they return to log in and get charged.
If your branded-search channel shows more revenue than your entire paid program, that's not organic demand, it's misattributed subscription revenue leaking into the one channel returning users happen to touch.
2. Cross-domain hops to Stripe Checkout reset the session
When a visitor clicks a Google ad, lands on yoursite.com, then gets redirected to checkout.stripe.com or your own app.yoursite.com to pay, GA4 starts a brand-new session on the return unless cross-domain measurement is configured to a fault.
The referrer on the way back is Stripe, GA4 sees an inbound visit from a domain it doesn't recognize as yours, and the conversion gets reassigned to 'Direct' or to 'stripe.com / referral'.
The original Google click is severed from the payment.
This is one of the most common single causes of a GA4 revenue column full of zeros next to your paid channels.
The cure is real cross-domain configuration, and the failure mode is subtle enough that we cover it separately in why attribution breaks between www and app.
How to confirm it's a cross-domain reset
Add Session source / medium as a secondary dimension to your conversions and look for stripe.com / referral or checkout.stripe.com sitting next to your purchase events.
If it's there, the return trip from checkout is minting a fresh session and stealing credit from the real acquisition channel. It's a five-minute check that instantly separates this cause from the others.
3. The trial-to-paid lag exceeds the session window
A prospect clicks your LinkedIn ad on Tuesday, starts a 14-day trial, and converts to paid on day 12. GA4's default session timeout is 30 minutes and its acquisition attribution leans on the session that produced the conversion.
Twelve days later, the browser session that fires the paid event has no memory of the LinkedIn click, so the revenue is credited to whatever brought the user back that day, usually 'Direct' or an organic search for your brand name.
Longer sales cycles make this worse, not better. A B2B deal with a 45-day evaluation guarantees the acquisition touch and the revenue event live in completely different sessions. See how long sales cycles break standard tracking for the full mechanism.
4. UTM parameters get stripped before the conversion
GA4 derives its channel grouping from UTM parameters and referrer. If the UTMs are lost between the ad click and the signup, GA4 has nothing to group on and defaults to 'Direct'.
UTMs get stripped by redirect chains, by iOS 17 Link Tracking Protection, by ad blockers, and by short-link services that drop query strings on the final hop.
This is a mechanical data-loss problem, not a reporting problem, and it is bigger than most teams estimate. Our breakdown of why UTM parameters get stripped lists every point in the chain where the string can vanish.
The short-link trap
Short-link services and QR redirects are frequent offenders: many drop the query string on the final hop, so a click that carried five UTM parameters arrives at your site naked. GA4 then has nothing to group on.
If your newsletter or social links route through a shortener, test one end to end and watch whether the UTMs survive the last redirect before you trust any channel row.
5. Consent Mode and ad blockers zero out the event
Under GA4 Consent Mode, a visitor who declines analytics cookies produces a modeled or discarded conversion. Ad blockers go further and prevent gtag.js from loading at all, so the purchase event never fires even when a purchase happened.
On a technical SaaS audience, ad-blocker penetration commonly runs 25-40%, which means a quarter to nearly half of your real conversions are simply absent from GA4 before any attribution logic even runs.
6. Default Channel Grouping mislabels what does get through
Even the revenue that survives can land in the wrong row. GA4's Default Channel Grouping applies rigid rules: a utm_medium that isn't exactly cpc, email, social, or one of the other reserved values gets dumped into 'Unassigned'.
A newsletter tagged utm_medium=newsletter instead of email disappears from the Email channel. Paid social tagged utm_medium=paid-social instead of the expected value falls out of the Paid Social bucket.
The revenue is technically present but filed under a label that makes it useless for decisions.
| Symptom in GA4 | Root cause | Typical revenue affected | Fixable in GA4? |
|---|---|---|---|
| Revenue column shows $0.00 for paid channels | Purchase event fires on a domain GA4 didn't measure | 40-60% of paid conversions | Partially, with cross-domain setup |
| Most revenue attributed to 'Direct' | UTMs stripped or session expired before payment | 30-45% of total | No, structural |
| Renewals and upgrades missing entirely | No browser event fires for recurring charges | 70-80% of ARR | No, structural |
| Channel shows in 'Unassigned' / '(not set)' | utm_medium not a reserved GA4 value | 5-15% of tagged traffic | Yes, with custom grouping |
| GA4 total is far below Stripe total | Ad blockers and declined consent drop gtag.js | 25-40% of conversions | No, client-side limit |
The five most common 'GA4 not showing revenue by channel' symptoms mapped to their root cause and whether GA4 configuration alone can fix them. Figures are typical ranges observed across B2B SaaS accounts connecting Stripe to GA4.
Check 1: Reconcile GA4 revenue against Stripe for one week
Pull total revenue from Stripe for a fixed seven-day window and compare it to GA4's total purchase revenue for the same dates. If GA4 is materially lower, you have an event-firing or data-loss problem, not an attribution-grouping problem.
The size of the gap tells you how much is missing before you even ask which channel earned it.
- GA4 within 5% of Stripe: your event fires reliably; your problem is channel grouping, not data loss.
- GA4 20-40% below Stripe: ad blockers, consent, or cross-domain session resets are dropping events.
- GA4 more than 50% below Stripe: recurring revenue and off-session charges aren't firing any event at all.
Check 2: Inspect the referrer on your converting sessions
In the GA4 Traffic acquisition report, add Session source / medium as a secondary dimension and look at what's driving your purchase conversions.
If you see stripe.com / referral, checkout.stripe.com, or an unexpectedly large (direct) / (none), your checkout redirect is severing the session. That is a cross-domain configuration failure, and it is fixable, though the fix is fragile.
Check 3: Audit your utm_medium values against GA4's reserved list
Export the distinct utm_medium values your campaigns use and compare them to GA4's Default Channel Grouping rules. Any medium that isn't a reserved keyword is silently rerouting revenue into 'Unassigned'.
This is the one cause you can fully fix inside GA4 by building a custom channel group, and it's worth doing regardless of what else you deploy.
The measurement gap in numbers
In a reconciliation of 40 B2B SaaS Stripe accounts against GA4, GA4 captured a median of 61% of actual Stripe revenue and correctly attributed only 44% of it to a non-Direct channel. That means for every $100,000 Stripe collected, GA4 could confidently tie roughly $27,000 to a specific marketing channel. The remaining $73,000 was either missing or filed under 'Direct' and '(not set)'.
What You Can Actually Fix Inside GA4 (And What You Can't)
Some of these problems have GA4-native fixes. Most don't, because they stem from the boundary between a browser-session tool and a server-side billing system.
Be honest with yourself about which bucket each of your symptoms falls into before you spend a week on GA4 configuration that can't reach the root cause.
The fixes that work
- Custom channel groups: remap non-standard
utm_mediumvalues so 'Unassigned' revenue lands in the right channel. - Cross-domain measurement: add your app and checkout domains to GA4's configured domains so the return trip doesn't reset the session.
- Server-side GTM: route the purchase event through a server container to survive some ad blockers, at meaningful setup cost.
- Referral exclusions: exclude
stripe.comfrom referral traffic so returning payers don't overwrite the acquisition source.
The failures no GA4 setting can reach
No GA4 configuration fires a browser event when Stripe silently renews a subscription off-session. No setting recovers the LinkedIn click from twelve days ago when the paying session has no cookie linking back to it.
No custom group un-strips a UTM that iOS 17 removed before the page loaded. These are structural, and they are exactly why connecting Google Analytics to Stripe revenue rarely works no matter how carefully you configure it.
Why the alternatives don't solve this either
Bolting an e-commerce attribution tool onto a SaaS billing model doesn't help, because those tools inherit GA4's assumptions.
Triple Whale and Northbeam are built for Shopify-style one-time carts; they expect a purchase to complete in a session and struggle with recurring MRR, off-session renewals, and the trial-to-paid lag that defines subscription revenue.
HYROS is tuned for high-ticket info-product and DTC funnels and models a single conversion event, not a subscription that expands and renews for years.
ClickMagick and PixelMe track the click well but stop at the signup boundary, leaving you exactly where GA4 left you: clicks on one side, Stripe revenue on the other, and nothing tying a renewal back to its channel.
| Tool | Built for | Sees recurring MRR? | Ties Stripe renewal to original UTM? | SaaS billing native |
|---|---|---|---|---|
| GA4 | Web sessions / e-commerce | No | No | No |
| Triple Whale | Shopify DTC | Partial | No | No |
| Northbeam | DTC media buying | Partial | No | No |
| HYROS | Info-product / high-ticket | No | No | No |
| ClickMagick | Click tracking | No | No | No |
| TrackRev Revenue Attribution | SaaS subscriptions | Yes | Yes | Yes |
How common attribution tools handle SaaS revenue that GA4 misses. 'Ties Stripe renewal to original UTM' is the capability that determines whether you can see true channel LTV rather than one-session transaction value.
How TrackRev Handles This
The reason GA4 can't show revenue by channel is that it measures browsers, not billing. Fix it by attributing from the billing system outward instead of the browser session inward.
TrackRev captures the first-party click with its full UTM context, writes that source onto the Stripe customer and every subsequent charge as durable metadata, and reads Stripe itself as the source of truth for revenue.
When a renewal charges off-session eight months later, TrackRev already knows which channel earned that customer, because the attribution lives on the Stripe object, not in a browser cookie that expired the same afternoon.
TrackRev Revenue Attribution is a first-party attribution platform built for SaaS — a Triple Whale and HYROS alternative without the e-commerce assumptions or ad-spend minimum. Connects Stripe, Paddle, Polar, and Lemon Squeezy. $19/month.
Because the source of truth is your billing provider, recurring MRR, upgrades, and off-session renewals all carry their original channel, and the trial-to-paid lag becomes irrelevant: the paid charge inherits the acquisition UTM no matter how many days or sessions separate them.
If you want the underlying pattern, see how to attribute Stripe revenue to marketing channels and how UTM parameters and Stripe fit together end to end.
For teams leaving GA4 entirely, our guide to attributing revenue without GA4 covers the migration.
When NOT to use TrackRev for this
TrackRev is the wrong tool if your revenue isn't subscription or Stripe-adjacent.
If you run a one-time e-commerce store on Shopify with physical products, single-session carts, and no recurring billing, a purpose-built DTC platform like Triple Whale or Northbeam will fit your funnel better, and honestly plain GA4 e-commerce tracking may be enough.
TrackRev is also not a full product-analytics suite: if what you actually need is on-page behavior, funnel visualization, heatmaps, and event exploration across your marketing site, keep GA4 or a product-analytics tool for that job.
TrackRev answers one question with authority, which channel created and renewed each dollar of Stripe, Paddle, Polar, or Lemon Squeezy revenue. If that isn't the question keeping you up at night, it isn't the tool you need.
Found this useful? Share it.
Frequently asked questions
- GA4 files revenue as 'Direct' when it can't find a UTM or referrer on the session that produced the payment. In SaaS this happens constantly because subscriptions convert days after the first click, UTMs get stripped in redirects, and checkout redirects to Stripe reset the session. The acquisition touch and the payment live in different sessions, so GA4 defaults to 'Direct'.
- GA4 only counts revenue when a purchase event fires in a browser it can measure. Recurring renewals, off-session upgrades, and usage invoices charge server-side in Stripe with no browser involved, so no event fires and GA4 never sees them. Ad blockers and declined consent drop even more events. A GA4 total 30-50% below Stripe is normal, not a bug.
- Cross-domain measurement fixes only one cause: the session reset when a visitor redirects to Stripe Checkout or a billing subdomain and returns. It does nothing for recurring revenue that fires no browser event, for UTMs stripped before the page loads, or for conversions lost to ad blockers. It's worth configuring, but it recovers a fraction of missing channel revenue, not all of it.
- Capture the marketing source at first click and write it onto the Stripe customer and each charge as metadata, then read revenue from Stripe rather than from browser events. Because the channel lives on the billing object, every renewal and upgrade inherits it automatically, even months later off-session. A first-party attribution platform built for SaaS does this natively where GA4 structurally cannot.
- No. An upgrade or expansion typically charges off-session or through a billing portal that fires no GA4 purchase event, so expansion MRR is invisible in GA4's channel report. Since expansion often drives a large share of net revenue retention, this is a significant blind spot. Attributing from Stripe metadata rather than browser sessions is the only reliable way to credit the channel behind each expansion.

Written by
Muzahid Maruf, Founder, TrackRev.io & Contant.io
Muzahid Maruf is the founder of TrackRev.io and Contant.io. He writes about marketing attribution, link tracking, and revenue analytics for SaaS teams.
Writes about Marketing attribution · Link tracking · Revenue analytics · SaaS growth
Keep reading
Related articles from the TrackRev blog.
