How to attribute Stripe revenue to marketing channels

Stripe attribution writes a visitor's source onto the payment in 6 steps. See where Stripe stores it, what to count as revenue and which tools do the join.

Muzahid Maruf — Founder of TrackRev.io

Muzahid MarufUpdated

Revenue attribution · 9 min read
On this page
  1. 01What Stripe stores about a sale
  2. 02Four ways to join a payment to a source
  3. 03How Stripe attribution works, step by step
  4. 04What the numbers look like after the join
  5. 05Choosing a window and a credit rule
  6. 06Stripe attribution tools compared
  7. 07Where the chain breaks
  8. 08What TrackRev does with a Stripe charge

Explore with AI

Opens this article inside the chosen assistant with a ready-made prompt.

Stripe attribution means attaching the marketing source of a visit to the Stripe payment it produced, so revenue can be totaled by channel.

A Checkout Session has no UTM field, and the Payment Links tracking guide describes UTM codes coming back on the redirect URL.

Your side has to carry the source from the browser to the charge, which takes a first-party cookie and a few server lines, then a report that groups paid invoices by what you stored.

In the illustrative numbers below, paid social brings 57.1% of the trials on a $39 plan and 19.1% of the net revenue, so ranking by signups would misplace budget.

Key takeaways

  • Stripe records no campaign for a sale. The source rides in client_reference_id (200 characters) or metadata (50 keys) that your server writes.
  • Metadata copies between Stripe objects only in a few cases, so write the source onto the Subscription or PaymentIntent whose events you will read.
  • Count revenue from invoice.paid, subtract the amount on each charge.refunded event, and wait for checkout.session.async_payment_succeeded on delayed methods such as ACH debits.
  • In the worked example (illustrative figures), paid social brings 57.1% of the trials on a $39 plan and 19.1% of net revenue. Crediting only first payments would cut the newsletter's share from 48.4% to 39.0%.

What Stripe stores about a sale

A sale spreads across a Customer, a Checkout Session, a PaymentIntent, a Charge and, for subscriptions, an Invoice each billing period. Each has a metadata field, and the metadata guide says it copies between objects only in the cases below.

Only secret-key requests return it, so your server does the writing.

FieldLimitWhere the value ends up
client_reference_id on a Checkout Session200 charactersThe Session and its checkout.session.completed event
metadata on any object50 keys, 40-character keys, 500-character valuesThe object you set it on
payment_intent_data.metadata in CheckoutSame as metadataThe PaymentIntent, then a one-time copy on its Charge
subscription_data.metadata in CheckoutSame as metadataThe Subscription, then a copy on every later Invoice
Metadata on a Payment LinkSame as metadataA snapshot on each Checkout Session the link creates
UTM codes on a Payment Link URL5 codes, 150 characters eachYour redirect URL

From Stripe's metadata, Checkout and Payment Links documentation, October 2026.

Metadata set on a Customer does not copy to its Charges. Write the source onto the object whose events you will read, when you create it.

Four ways to join a payment to a source

The first and third routes need no checkout code, but the second is the one I would build, because only it stores a journey you own.

Google's Measurement Protocol guide asks for server events within 48 hours of the browser event, so renewals strain the fourth route. The Google Analytics guide has the build.

RouteCodeKeepsBreaks when
One Payment Link per channelNoneThe channel, as link metadataPlacements outnumber links
Visitor ID in Stripe CheckoutA few server linesThe stored journeyPayments skip your server
Customer emailNoneAny flow with matching emailsSignup and payment emails differ
GA4 purchase eventA webhookGoogle's channel reportsRenewals arrive late

How Stripe attribution works, step by step

The visitor ID route has 6 links, and a break in any one sends revenue to an unattributed row.

Give each placement its own lowercase UTM values: Google's Analytics Help page says parameter values are case sensitive, so Newsletter and newsletter count as 2 sources. Have your server set the cookie.

WebKit's cookie rules say Intelligent Tracking Prevention deletes JavaScript-created cookies after 7 days without interaction, and caps cookies set in an HTTP response at 7 days only when it detects third-party CNAME or IP address cloaking.

Step 2: Tie the visitor to an account at signup

Store the visitor ID, first-touch source and email on the user record. A buyer who clicks on a phone and pays on a laptop holds 2 cookies, and the email links them.

Step 3: Write the visitor ID into Stripe when checkout starts

Create the Stripe Checkout Session when the buyer clicks Buy, because it stays open for 30 minutes to 24 hours and one built at page load carries whatever the cookie held then.

Put the ID in client_reference_id and in metadata, with subscription_data.metadata for subscriptions and payment_intent_data.metadata for one-time payments. The Checkout attribution guide has the route and the metadata setup guide has key names.

A Payment Link skips your server, so append client_reference_id to its URL. Stripe accepts letters, digits, dashes and the _ character up to 200 characters, which fits a 36-character UUID. The Payment Links attribution guide covers the rest.

Step 4: Read the money from webhooks

Stripe's subscription webhook guide says invoice.paid is sent when an invoice is successfully paid. Each new invoice gets a copy of the subscription's metadata under parent.subscription_details.metadata, so payment 12 of a $39 plan carries the source written for payment 1.

Live mode retries a failed delivery for up to 3 days, so store each event ID under a unique index.

EventFires whenAction
checkout.session.completedStripe Checkout finishesLink visitor ID to customer
invoice.paidAny invoice is paidBook the revenue once
charge.refundedA full or partial refundSubtract the amount

Events from Stripe's subscription and refund documentation, October 2026.

A completed Checkout Session is not always a settled sale

Stripe's Checkout fulfillment guide says ACH direct debit and other delayed methods fire checkout.session.async_payment_succeeded only once the payment succeeds, so credit a channel on that event.

Step 5: Group paid invoices by source, net of refunds

Credit one amount and write the rule down. A Checkout Session reports amount_subtotal, amount_total and total_details.amount_tax, so the pre-tax figure is easy to isolate.

Stripe's refund guide says a charge can take several refunds and the original processing fee is not returned, so keep gross and net in separate columns.

Revenue by channel from your own payments and refunds tables (SQL)
-- payments: one row per paid invoice or one-time charge, filled from the webhook-- refunds: one row per charge.refunded amount, linked to the paymentwith refunded as (  select payment_id, sum(amount_cents) as cents  from refunds  group by payment_id)select  coalesce(p.source, 'unattributed')                   as channel,  count(distinct p.customer_id)                        as customers,  sum(p.amount_cents) / 100.0                          as gross,  sum(coalesce(r.cents, 0)) / 100.0                    as refunded,  sum(p.amount_cents - coalesce(r.cents, 0)) / 100.0   as netfrom payments pleft join refunded r on r.payment_id = p.idwhere p.livemode  and p.paid_at >= date '2026-07-01'group by 1order by net desc;

Step 6: Test the chain in a sandbox

Click a tagged link in a private window, sign up and pay with Stripe's test card 4242 4242 4242 4242 and a future expiry such as 12/34. Then refund it: the channel should gain the amount and lose it again.

What the numbers look like after the join

Take a $39 monthly plan and 90 days of sales from 3 channels. The figures are invented to show the arithmetic, so replace them with your own.

ChannelTrials (share)Paid invoicesRefunded invoicesNet revenue (share)
Paid social400 (57.1%)344$1,170 (19.1%)
Search ads180 (25.7%)543$1,989 (32.5%)
Newsletter120 (17.1%)782$2,964 (48.4%)
Total7001669$6,123

Net revenue is paid invoices minus refunded invoices, times $39, over 90 days. Illustrative figures.

Paid social leads on trials, with 400 of 700. It earns $1,170 of the $6,123, while the newsletter's 120 trials return $2,964. Per trial, that is $24.70 for the newsletter, $11.05 for search ads and under $3 for paid social.

Paid social also refunded 4 of 34 invoices, or 11.8%, against 2.6% for the newsletter, so gross revenue would have flattered it by $156.

Renewals shift the picture again. If a report credits only each customer's first payment, the newsletter's share falls from 48.4% to 39.0%, because its customers paid 2.6 invoices each against 1.7 for paid social.

The subscription LTV guide covers 3 ways to credit renewals.

ChannelPaying customersInvoices per customerFirst payments only (share)Net revenue (share)
Paid social201.7$780 (26.0%)$1,170 (19.1%)
Search ads272.0$1,053 (35.1%)$1,989 (32.5%)
Newsletter302.6$1,170 (39.0%)$2,964 (48.4%)

First payments are paying customers times $39, before refunds. Same 90 days of sales as above.

Choosing a window and a credit rule

TrackRev's attribution benchmarks put the median time from first click to first paid charge at 6.3 days and the 90th percentile at 48.2 days. Those counts include only conversions inside each workspace's window, so the true tail runs longer.

Pull the click-to-payment gap for your last 100 customers and set the window just past the 90th percentile.

Last touch gives the closing click all the credit, first touch gives it to the introducer, and linear splits it evenly, so a sale touched by 2 channels counts 0.5 on each.

In the Q2 2026 data, 64% of TrackRev workspaces default to last touch, 22% to linear and 14% to first touch. The attribution models comparison matches each rule to a funnel.

Stripe attribution tools compared

The Sigma guide says Stripe Dashboard financial reports can include metadata and Sigma's templates leave it out, with a Metadata to column template to add it.

Sigma runs ANSI SQL, shows up to 1,000 rows, exports all of them to CSV and costs nothing in a sandbox.

Stripe Sigma billingCharges included a monthPrice a monthEach additional charge
MonthlyNot stated$156¢
Annual250$104¢
Annual2,500$602.5¢
Annual10,000$2252.5¢
Annual25,000$4502¢

From Stripe's Sigma pricing page, October 2026. New users get a 30-day free trial.

ApproachSees the clickRenewals and refundsEffort
Stripe Dashboard reports or Stripe SigmaNo, only stored metadataYes, in Stripe's dataA query plus the metadata write
Your own webhook and databaseYes, once you build the click logYes, from invoice.paid and charge.refundedAn endpoint, 2 tables and a report
Google Analytics 4 with the Measurement ProtocolYes, inside GA4Limited by the 48-hour windowA webhook and a GA4 property
A billing-side tool such as TrackRevYes, via pixel and tracked linksYes, renewals credit the first clickA pixel and a restricted key

Where the chain breaks

SymptomCauseFix
Your total differs from Stripe's reportStripe Dashboard reports default to your local time zone, Sigma templates use UTC, and a day's balance report publishes by 12:00 pm the next dayMatch the time zone and compare after noon
Test payments inflate a channelTest events arrive with livemode falseSkip them in production queries
One buyer shows up as 2 channelsA phone click and a laptop payment leave 2 cookiesJoin on the email saved at signup

Causes from Stripe's reporting and Sigma documentation, October 2026.

What TrackRev does with a Stripe charge

TrackRev Revenue Attribution reads Stripe with a restricted key, so checkout code can stay as it is.

The first sync reads the previous 30 days of charges, a scheduled job picks up new ones, and a webhook that TrackRev registers when the key allows it starts a sync on a successful charge, a refund or a completed Session.

For each charge it checks a vid key in the charge metadata, then the Session's client_reference_id or metadata, then the buyer's email, which the pixel binds to the visitor at signup or checkout.

A renewal inherits the first order's credit, and a charge with any refund is marked refunded on the next sync, so even a partial refund removes the whole charge.

Credit defaults to last touch, with first touch and linear available, and the window runs from 1 to 365 days, 30 by default.

Revenue figures need a paid plan, from Starter at $39 a month. The free plan is link tracking only, with 50 links and 1,000 tracked events a month. The Stripe integration page covers the pixel and the key permissions.

Pick something else when your payments run through none of Stripe, Paddle, Polar or Lemon Squeezy, or when you close a handful of sales a month. A metadata write and a spreadsheet will answer the question.

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

Stop guessing where your revenue comes from.

Set up TrackRev in about five minutes. The free plan covers 1,000 events a month, no card needed.

Start free