Revenue
Stripe revenue by traffic source
Stripe takes the payment. traffic.cx tells you which visit, source and campaign it came from. Connect Stripe with a restricted key, pass one ID from the visit into your checkout, and every payment, renewal and refund shows up next to the traffic that earned it. Payments that can't be linked stay in your totals as "Unattributed", so your revenue still matches what Stripe received.
Last updated
Last updated 28 October 2026. Setup details come from the Stripe setup guide and revenue docs. Need the step-by-step technical guide? Go to /integrations/stripe.
In short
- Connect: create a Stripe restricted key with five permissions and paste it in Settings → Revenue. traffic.cx creates the webhook and imports the last 90 days of payments.
- Link: pass the visitor's pageview ID (
tcx_pvid) into Checkout Session metadata, and into the subscription's metadata so renewals carry it. For Payment Links, pass it asclient_reference_id. - Read: revenue, paying customers, conversion rate and revenue per visitor by channel, source, campaign, landing page, country and device.
- Cost: included on every plan, Free too: one site, 3,000 events a month, no card.
What Stripe payments look like in traffic.cx
traffic.cx reads Checkout Sessions, Payment Links, PaymentIntents, subscription invoices and refunds. Each payment is matched to a recorded visit, and the Revenue page shows, for each channel, source, campaign and landing page:
| Metric | Definition |
|---|---|
| Revenue | Payments minus refunds, in the site's currency, by payment time |
| Paying customers | Distinct customers who paid in the period |
| Conversion rate | First-time buyers ÷ unique visitors |
| Revenue per visitor | Revenue ÷ unique visitors |
| Average order value | Revenue ÷ payments that aren't refunds |
| LTV | All the revenue so far of the customers first won in the period, per customer |
Payments in other currencies are converted to your site's reporting currency using historical European Central Bank reference rates. With Stripe, traffic.cx counts the amount Stripe reports; it doesn't remove sales tax the way merchant-of-record providers do (definitions).
How a Stripe payment finds its visit
- The visit. The traffic.cx tracker records the visit with its source, campaign and landing page.
- The checkout. When the visitor starts checkout, your page reads
trafficcx.pageviewId()(and, in cookie mode,trafficcx.visitorId()) and your server adds them to the Checkout Session's metadata. - The payment. Stripe sends the payment to traffic.cx. traffic.cx finds the pageview, then credits the right visit using your attribution model: last non-direct (default) or first touch, within a lookback of 90 days by default (7 to 365 days).
- Renewals. A renewal for a known customer inherits the attribution of that customer's first payment, so a subscriber who came from a newsletter keeps crediting the newsletter.
- Refunds. A refund is subtracted on the day it happens and credited to the payment it refunds.
- No link. A payment with no matching visit or earlier customer payment stays in the totals as Unattributed.
In the default cookieless mode, the pageview ID links a payment to the visit where checkout started; daily-rotating visitor IDs don't connect visits across days. Longer journeys need the optional cookie mode (same browser only) or an earlier payment from the same customer (cookieless vs cookie mode).
Connect Stripe in three steps
Install and verify the tracker first. You need an owner or admin role in traffic.cx and access to create a Stripe restricted key. Use a separate traffic.cx test site with a Stripe test-mode key while you set up.
1. Create a restricted key and connect
In Stripe, open Developers → API keys → Create restricted key, with these permissions and nothing else:
| Resource | Access |
|---|---|
| Checkout Sessions | Read |
| Invoices | Read |
| PaymentIntents | Read |
| Refunds | Read |
| Webhook Endpoints | Write |
In traffic.cx, open Settings → Revenue, choose Connect next to Stripe and paste the key. traffic.cx checks each permission, creates a webhook endpoint in your Stripe account, stores its signing secret encrypted, and imports the last 90 days of payments. Imported payments without visit IDs count as Unattributed.
2. Pass the visitor's IDs into checkout
Put tcx_pvid (and tcx_vid in cookie mode) in the Checkout Session's metadata. For subscriptions, also put them in subscription_data.metadata, so renewals carry them. For one-off payments, session metadata is enough; with your own PaymentIntents, put the keys in the PaymentIntent's metadata. The Stripe guide has the server code, and the revenue docs show how to read the IDs in the browser and validate them on your server.
Payment Links: when the visitor clicks the link, add the pageview ID as client_reference_id with a tcx_ prefix. Don't use this if client_reference_id already carries another reference your app needs.
3. Test one payment
Open a tagged page on your site (for example with ?utm_source=setup-check&utm_medium=email&utm_campaign=integration-test), start checkout from that visit, and complete a Stripe test-mode payment. In Settings → Revenue, check the webhook log, then find the payment on the Revenue page with the right source and campaign. For a subscription, check the first invoice, a renewal and a refund too.
The Stripe details traffic.cx handles
| Stripe event | Recorded as |
|---|---|
checkout.session.completed, checkout.session.async_payment_succeeded | The payment (its PaymentIntent, or the subscription's first invoice), with the session's metadata |
payment_intent.succeeded | A one-off payment (PaymentIntents that belong to an invoice are counted with the invoice) |
invoice.paid | A subscription start or renewal |
refund.created, refund.updated | A refund; failed or canceled refunds are removed |
- Counted once. Each payment is recorded once, however many of these events describe it.
- Missed webhooks. Failed deliveries are retried with growing pauses, and an hourly sync reads the last two days again.
- Pinned API version. The webhook endpoint is pinned to Stripe API version
2024-06-20; don't change it independently of the connector. - Disconnecting removes the webhook endpoint; payments already recorded stay.
When a payment shows as Unattributed
- A Stripe connection alone doesn't supply browser IDs. Check the actual session or PaymentIntent metadata for
tcx_pvid. - The tracker was blocked, or checkout ran before it loaded, so there was no pageview ID.
- The buyer returned on a later day or another device in cookieless mode.
- It's an imported payment from before you installed traffic.cx.
The UTM campaign guide walks through fixing Unattributed revenue.
Pricing
Sign up with Google or email and start on the Free plan: every feature on one site, no card and no trial clock. Revenue attribution is included on every plan, Free too. Paid plans add more events, more sites, your full history, the API and teams. A payment received through a provider integration doesn't count as an event. See pricing.
See which traffic pays you
Start free · Stripe setup guide · How revenue attribution works · Pricing
Using another provider? See Lemon Squeezy, Polar, Dodo Payments or the Payments API.
Frequently asked questions
How do I see which traffic source my Stripe revenue comes from?
Install the traffic.cx script, connect Stripe with a restricted key in Settings → Revenue, and pass the visitor's pageview ID into your Checkout Session metadata. traffic.cx then credits each payment to the visit's source, campaign and landing page.
Does it work with Stripe subscriptions and renewals?
Yes. Put the IDs on the subscription's metadata too. A renewal for a known customer inherits the attribution of that customer's first payment, so it keeps crediting the source that brought them.
Does it work with Stripe Payment Links?
Yes. Add the pageview ID to the link as client_reference_id, with a tcx_ prefix, when the visitor clicks. Don't use this if that field already carries another reference your app needs.
What permissions does the Stripe key need?
A restricted key with read access to Checkout Sessions, Invoices, PaymentIntents and Refunds, and write access to Webhook Endpoints, so traffic.cx can create its webhook. Nothing else.
Are refunds subtracted?
Yes. Refunds are subtracted on the day they happen and credited to the payment they refund. Revenue in traffic.cx is always payments minus refunds.
Do I need cookies for Stripe attribution?
No. In the default cookieless mode, the pageview ID links a payment to the visit where checkout started. The optional cookie mode lets traffic.cx link visits across days in the same browser. Whether you need consent depends on your setup and the rules that apply to you.