Blog
Stripe attribution: connect a payment to its traffic source
A practical guide by the AnalyticFast Team. Examples are illustrative; this article reports no original research or customer performance results.
When a Stripe payment has no acquisition source, inspect the identity handoff before adding more client-side purchase events. Your website knows the visit. Stripe knows the financial event. Attribution requires a deliberate connection between them.
Separate three identities
A visitor ID identifies browser analytics context. A Stripe Customer ID identifies the customer within Stripe. A PaymentIntent ID identifies a financial transaction for this integration. They serve different purposes. Do not replace an application’s client_reference_id or customer key with analytics data just because a checkout accepts a reference field.
Put metadata on the object the receiver reads
Stripe does not copy arbitrary metadata between every related object. For a one-time Checkout payment, use payment_intent_data.metadata so the successful PaymentIntent carries ml_visitor_id and ml_session_id. Session-level metadata alone is not enough. For a subscription, subscription_data.metadata can supply later invoice context. See Stripe’s propagation rules and the complete AnalyticFast Stripe setup.
// Browser, just before your existing server checkout request:
const ids = window.analyticfast?.attribution?.() ?? {};
// Send only present IDs as optional context.
// Your server validates them, keeps price selection under server control,
// and passes them through the Stripe metadata fields for the chosen mode.
Do not manufacture analytics IDs when the tracker is unavailable. Payment must continue even if attribution is missing. Keep the Stripe secret key, webhook signing secret and server API tokens out of browser code. The public Site ID is the only installation identifier your page needs.
Use the canonical financial event
The current adapter creates money from payment_intent.succeeded, keyed by the PaymentIntent ID. invoice.paid enriches attribution, product context and renewal classification; it does not add another sale. Configure both events along with refund.created and refund.updated. An invoice with no PaymentIntent reference is outside this adapter’s financial coverage. These are snapshot event contracts; thin events are unsupported. Stripe documents destination setup in its webhook guide.
Check the source allocation after matching
Matching a visitor is separate from selecting a session. If someone first arrives from Reddit, later visits through a newsletter and finally returns directly to buy, the default last non-direct model credits the newsletter. The first-touch view credits Reddit. A source change after switching models is not evidence of duplicated revenue.
Use a test matrix instead of one success-page check
- One-time payment: verify present metadata on the signed PaymentIntent and one recorded payment.
- Subscription: check the first charge and a later invoice cycle, including the invoice’s PaymentIntent reference.
- Replay: redeliver a financial event and confirm its total stays stable.
- Refund: test a successful partial/full refund; pending or failed refund resources must not subtract revenue.
- Missing tracker: let checkout complete with empty optional IDs, then confirm the payment is retained with whatever attribution evidence is available.
Use a separate analytics test site and Stripe’s test environment. A local parser preview is useful for payload shape; it does not validate the delivery path. Once the matrix passes, reconcile live payments by currency and date without equating analytics net revenue with a payout after Stripe fees.
Add your website to AnalyticFast, or start with the installation guides and payment integrations.
Questions, answered.
Does Checkout Session metadata automatically reach the PaymentIntent?
No. For a one-time Checkout payment use payment_intent_data.metadata. Subscription mode has its own metadata path. Check Stripe’s documented propagation rules rather than assuming all related objects share metadata.
Should I record revenue again on checkout.session.completed?
Not for this integration. Its financial identity is the successful PaymentIntent. Adding another client or session-based revenue event can duplicate the same sale.
Keep exploring
AI crawlers and AI referrals are different measurements
Separate AI bot requests from people clicking assistant links, understand what a browser tracker misses, and avoid treating crawl activity as revenue evidence.
Read guide BlogDataFast alternatives: evaluate the revenue tracking workflow
Compare analytics options by payment coverage, attribution handoff, refunds, site access and operating effort, with a practical migration acceptance checklist.
Read guide BlogGA4 alternatives for indie hackers: choose by the decision
Choose website, revenue or product analytics by the question you need to answer, and compare metric definitions before replacing a working GA4 setup.
Read guide