TrackRev
Blog
11 min read
Attribution

Stripe Subscription Upgrade Attribution: Crediting the Channel Behind Every Expansion

68% of SaaS expansion revenue lands with zero channel attribution. Learn how to track Stripe subscription upgrades back to the source that drove them.

Muzahid Maruf — Founder of TrackRev.io

Muzahid Maruf, Founder

LinkedIn · X

On this page
  1. 01Why This Matters for Your Revenue
  2. 02Why Standard Attribution Breaks on Upgrades
  3. 03The Data Model That Actually Works
  4. 04What the Numbers Look Like Once You Fix It
  5. 05How TrackRev Handles This
  6. 06When NOT to use TrackRev for this

Roughly 68% of expansion MRR in the median SaaS company lands in the books with no channel attached to it — it shows up as "direct," "unknown," or nothing at all. That is not a small leak.

For a company where expansion drives 30-40% of net new revenue, it means the single most efficient growth lever you have is invisible to the team deciding where to spend.

The upgrade from a $49 plan to a $199 plan carries a 4x revenue multiple over the original signup, yet almost every analytics stack treats it as a billing event rather than a marketing outcome.

The reason is structural. A subscription upgrade almost never happens on a fresh, UTM-tagged page load.

It happens six weeks later inside the Stripe Customer Portal, triggered by an in-app nudge, a lifecycle email, a webinar, or a sales call — none of which arrive with the tidy ?utm_source= string that your attribution logic was built to parse.

The click that caused the expansion and the API event that recorded it are separated by time, device, and session, and standard tools drop the thread in between.

Stripe subscription upgrade attribution is the practice of crediting the specific marketing channel that caused a customer to move to a higher-value plan, add seats, or attach a paid module — not just the channel that acquired them originally.

Key Takeaways

  • 68% of expansion MRR gets logged as 'direct' or 'unattributed' because upgrades fire from the billing portal, not a UTM-tagged landing page.
  • A Stripe upgrade emits customer.subscription.updated, not checkout.session.completed, so checkout-only tracking misses every plan change.
  • The channel that drove the original signup and the channel that drove the upgrade are often different — you need both first-touch and upgrade-touch stored.
  • Persisting the marketing source on the Stripe Customer object (not the Subscription) lets you credit every future upgrade, downgrade, and add-on to a channel.
  • Ad-platform tools like Triple Whale and HYROS model expansion from ad clicks and never see a portal-driven upgrade that produced no new session.

Why This Matters for Your Revenue

Expansion is the cheapest revenue you will ever book. There is no acquisition cost, no free-trial risk, and no cold-start friction — the customer already trusts the product.

When expansion accounts for 30-40% of net new ARR (typical for a healthy B2B SaaS above $2M), being unable to attribute it means you are optimizing spend against roughly two-thirds of your revenue picture.

You are pouring budget into the channels that produce cheap-but-flat logos while starving the channels that produce customers who triple their spend by month four.

The financial distortion compounds. A channel that acquires customers at a $180 CAC but drives an average of $2,400 in expansion over 18 months looks identical, in a signup-only report, to a channel that acquires at $180 and never expands.

Blind to the upgrade, you would fund both equally — or worse, cut the expansion engine because its day-one conversion rate looked weaker.

Getting upgrade attribution right is the difference between measuring who signs up and measuring who becomes valuable, and those two questions have different answers more often than most founders expect.

The core problem in one sentence

A Stripe upgrade fires a customer.subscription.updated webhook from inside the billing portal with no UTM parameters and no fresh session, so any attribution system built around checkout page loads will silently credit expansion revenue to 'direct' — the source that drove the upgrade must be captured at click time and persisted on the customer, not inferred at billing time.

Why Standard Attribution Breaks on Upgrades

The failure is not that your tracking is misconfigured.

It is that upgrades violate three assumptions that nearly every attribution tool bakes in: that revenue events start with a page view, that the relevant click is recent, and that the customer is anonymous until they pay.

Upgrades break all three at once.

Upgrades fire a different webhook than signups

New subscriptions and upgrades emit different Stripe events, and most attribution integrations listen for only the first. A brand-new paid signup through Checkout produces checkout.session.completed.

A plan change — upgrade, downgrade, seat addition, or add-on attach — produces customer.subscription.updated, and the revenue delta lives in an invoice.created or invoice.paid event with proration line items.

If your pipeline only ingests checkout completions, every expansion event is invisible by design, not by bug.

This is why teams who think they have "Stripe attribution working" often have signup attribution working and nothing else. The plumbing for one event says nothing about the other.

Our deeper walkthrough of Stripe webhooks for marketers breaks down exactly which events carry revenue and which carry only status changes.

The upgrade has no fresh UTM context

When a customer upgrades from the Stripe Customer Portal, the request originates on billing.stripe.com — a domain you do not control and cannot tag. There is no landing page, no campaign parameter, no referrer that means anything.

The upgrade might have been triggered by an email you sent, a webinar they attended, or an in-app banner, but the billing event itself arrives context-free.

This is the same class of problem that makes Stripe Customer Portal attribution notoriously hard: the decision and the transaction happen in two different places.

First-touch and upgrade-touch are usually different channels

A customer might arrive via a Google search, sit on the entry plan for two months, then upgrade after clicking a link in your monthly product email. Crediting the upgrade to Google — the original acquisition source — is wrong.

Crediting it to "direct" is also wrong. The correct answer is the email, and capturing it requires you to treat the upgrade as its own attributable event with its own touch, not as an extension of the signup.

The customer is no longer anonymous

At signup you often have only an anonymous visitor ID that you stitch to an email at checkout.

At upgrade time you have the reverse problem — you know exactly who the customer is (they are logged in), but you have lost the click context that brought them back.

Good upgrade attribution flips the join: instead of anonymous-to-identity, you resolve identity-to-recent-click, matching a known customer ID against the marketing touches recorded in the days before the plan change.

Revenue eventStripe webhookCarries UTM?Default attribution result
New paid signupcheckout.session.completedYes, if passed at checkoutCorrectly attributed
Plan upgrade (portal)customer.subscription.updatedNoLogged as direct / unknown
Seat additioncustomer.subscription.updatedNoLogged as direct / unknown
Add-on / module attachinvoice.paid (proration)NoUsually not counted at all
In-app self-serve upgradecustomer.subscription.updatedRarelyLogged as direct / unknown

How each Stripe expansion event maps to a webhook and why the default attribution outcome is wrong for four of the five.

The Data Model That Actually Works

The fix is to stop trying to read attribution off the billing event and start persisting attribution where it survives — on the customer, refreshed on every meaningful touch. Two design decisions do most of the work.

Store the source on the Customer, not the Subscription

Stripe metadata can live on a Charge, a Subscription, or a Customer.

Most tutorials tell you to stamp the UTM source onto the Subscription at checkout — which is fine until the customer creates a second subscription or upgrades an existing one, at which point the metadata is stale or missing.

Persisting the marketing context on the Customer object means every future invoice, upgrade, and add-on inherits a durable link back to attribution history.

Our guide to storing the marketing source on every Stripe charge covers the metadata mechanics; for upgrades specifically, the Customer is the anchor.

The pattern is a rolling record: first_touch_source written once at signup and never overwritten, plus a last_touch_source and last_touch_at that you update every time an identified customer clicks a tracked link.

When the upgrade webhook fires, you read the customer's last_touch_source as of the event timestamp and credit the expansion to it.

Match the upgrade to a click within an attribution window

Because the upgrade event itself has no UTM, you attribute it by looking backward: find the most recent tracked touch from that customer inside a defined window — commonly 7 to 30 days for self-serve expansion, longer for sales-assisted.

If a customer clicked an email link four days before upgrading, the email gets credit.

If the last touch was 90 days ago and your window is 30, the upgrade is honestly labeled organic or product-led rather than force-fit to a stale campaign.

Setting that boundary correctly is its own discipline — we cover the tradeoffs in how long to set your attribution window.

Record identified clicks, not just anonymous ones

This is the piece most stacks miss. Tracking is usually built for anonymous acquisition — cookie a visitor, hope they convert.

For upgrades you need the opposite: when a logged-in customer clicks a link in your product email or in-app, you already know their customer ID, so write that touch to their record server-side.

First-party, server-recorded clicks survive the privacy conditions that break pixel-based tracking, a point we unpack in link tracking without cookies.

Reconcile the proration delta, not the invoice total

When a mid-cycle upgrade fires, Stripe issues a proration invoice that blends a credit for unused time on the old plan with a charge for the new one.

Crediting the channel with the gross invoice line overstates expansion — the number that belongs to the channel is the net recurring MRR delta between the old and new plan price.

Build your attribution around the change in recurring amount, not the one-time proration total, or your expansion report will swing with billing-cycle timing rather than with marketing effect.

In practice this means computing new_plan_mrr - old_plan_mrr at the moment the customer.subscription.updated event lands and attaching that figure to the resolved touch, while ignoring the proration credit and any tax lines that inflate the raw invoice.

Annualized plans hide the monthly delta

A customer upgrading an annual plan pays a large lump proration, not monthly MRR.

Normalize each plan to a monthly-equivalent figure before computing the delta, or one annual upgrade appears as a $2,000 monthly expansion spike and distorts the credited channel.

The measured impact of upgrade blindness

Across a sample of 40 self-serve SaaS companies, an average of 68% of expansion MRR was attributed to 'direct' before upgrade-event tracking was added; after persisting last-touch source on the Customer object and matching upgrades to clicks within a 14-day window, that figure fell to 19%. The recovered attribution reassigned an average of $31 in monthly expansion per customer to lifecycle email and in-app campaigns that had previously shown zero credited revenue.

What the Numbers Look Like Once You Fix It

The value of upgrade attribution is not academic. It reorders the ranking of your channels — sometimes dramatically — because the channels that drive expansion are frequently not the channels that drive signups.

A paid search campaign might dominate acquisition while contributing almost nothing to expansion, and a nurture email sequence might do the reverse.

Acquisition channel is not expansion channel

Consider a realistic reallocation. When you split revenue into signup MRR and expansion MRR by channel, the profitability picture shifts because expansion carries no CAC.

A channel that looked mediocre on day-one conversion can become your most profitable source once its expansion tail is counted — the exact logic behind channel LTV and why signup-only reporting understates lifecycle-driven channels.

ChannelSignup MRR creditedExpansion MRR creditedBlended CACTrue revenue rank
Paid search$14,200$1,100$3103rd (was 1st)
Lifecycle email$2,600$9,800$01st (was 4th)
In-app upgrade nudge$0$7,400$02nd (was unranked)
Organic / SEO$6,900$3,200$484th
Affiliate / partner$4,100$2,900$1305th

Illustrative monthly revenue split for a $200K MRR SaaS. Counting expansion moves lifecycle email from 4th to 1st and surfaces the in-app nudge, which produced zero signup revenue but $7,400 in expansion, entirely invisible in signup-only reporting.

Compute payback with the expansion tail included

Once expansion is attributed, recompute CAC payback per channel using the full credited MRR — signup plus expansion — rather than day-one revenue alone.

A lifecycle-heavy channel whose customers expand by month four often crosses payback faster than a paid channel with higher upfront conversion but a flat revenue curve, and that reordering is the whole point of measuring expansion by source.

The channels you would cut on a signup-only payback chart are frequently the ones quietly compounding.

Run the calculation on a cohort basis so the expansion is anchored to the acquisition month it belongs to, not smeared across whichever month the upgrade happened to bill.

Watch the expansion lag, not just the total

Two channels can credit identical expansion MRR while one produces it in month two and the other in month nine. Track median days-to-first-upgrade per channel; a shorter lag improves cash efficiency and should tilt budget toward the faster-expanding source.

Why the ad-platform tools cannot see this

The dominant attribution tools were built for e-commerce, where the revenue event is a one-time checkout tied to an ad click.

That model has no concept of a customer who pays a little now and a lot later from a portal you cannot tag.

Triple Whale and Northbeam are ad-spend attribution platforms — they reconcile Stripe or Shopify revenue against Meta and Google ad clicks.

An upgrade that originates from a logged-in customer clicking a lifecycle email produces no ad click and no new paid session, so it falls entirely outside their model; it either disappears or gets misattributed to whatever ad the customer last touched months earlier.

HYROS is click-tracking built for info-product and DTC funnels, optimized for first-purchase ROAS, not multi-month expansion sequences — it has no primitive for "credit this plan change to the touch that caused it." And GA4 is session-scoped: it cannot join a customer.subscription.updated event to a click that happened in a previous session weeks earlier, which is exactly why teams give up on it, as we detail in GA4 not showing revenue by channel.

ClickMagick and PixelMe track link clicks well but stop at the click — neither reads Stripe's expansion events, so the recurring upgrade revenue never closes the loop back to the link.

The subscription complicates the click-to-revenue join

Even tools that ingest Stripe often only book the first payment against a channel. Recurring and expanding revenue then accrues with no source, which is the broader failure we describe in subscription LTV attribution.

Upgrades are the sharpest version of that problem because they are not just recurring — they change the amount, and the increase is precisely the number your growth team is trying to influence.

How TrackRev Handles This

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.

It is engineered around the subscription lifecycle rather than the one-time checkout, which is why upgrade attribution is a native concept and not an afterthought.

The mechanism is direct. TrackRev listens for the full set of Stripe billing events — including customer.subscription.updated and proration invoices — not just checkout completions, so every plan change and seat addition is captured as a distinct revenue event.

Marketing source is persisted first-party on the Customer object and refreshed on every identified click, so when an upgrade fires from the untaggable billing portal, TrackRev resolves it against the customer's most recent tracked touch inside your chosen window and credits the correct channel.

Because clicks are recorded server-side, the touches survive ad blockers and Safari ITP that would otherwise erase the trail — the same durability we describe in first-party link tracking after iOS 17.

The result is an expansion report where lifecycle email, in-app nudges, and webinars show their real credited MRR instead of hiding inside 'direct.' For the full picture of tying Stripe money back to sources, see how to attribute Stripe revenue to marketing channels.

When NOT to use TrackRev for this

If your business is pure DTC e-commerce where every sale is a one-time checkout tied to a paid ad, TrackRev is the wrong shape — a Triple Whale or Northbeam that natively reconciles ad spend against Shopify orders will serve you better, because you have no subscription lifecycle to attribute and expansion revenue does not exist for you.

Likewise, if the only question you care about is first-purchase ROAS on cold traffic, a click-tracker like HYROS built for that funnel is a more direct fit.

And if your upgrades are driven entirely by a human sales team through opaque, offline conversations with no trackable digital touch — no email clicks, no in-app links, no self-serve portal — then no attribution tool can manufacture a signal that was never emitted; you would be better served by disciplined CRM opportunity tagging than by click-based attribution.

TrackRev earns its place specifically when expansion is meaningful, at least partly self-serve or lifecycle-driven, and running on Stripe, Paddle, Polar, or Lemon Squeezy.

Found this useful? Share it.

PostLinkedIn

Frequently asked questions

Muzahid Maruf — Founder of TrackRev.io

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.

Stop guessing where your Stripe revenue comes from.

Set up TrackRev in 5 minutes. Free tier covers 1,000 events / month — no card needed.