Revenue Expansion beta

Send Stripe metadata that Revenue Linter can read.

Add stable user IDs and UTM-style attribution to Stripe Checkout, Subscriptions, Customers, or PaymentIntents. Revenue Linter reads the metadata later to group active subscriptions, silent churn, and upgrade-ready accounts by campaign.

Recommended fields

Use consistent keys before the customer pays.

Metadata should be stable and non-sensitive. Do not store ad platform tokens, session cookies, raw IP addresses, personal notes, or secrets in Stripe metadata.

appUserIdutm_sourceutm_mediumutm_campaignutm_contentutm_termlanding_pagereferrersignup_source

Subscription Checkout

Attach attribution to the Checkout Session and Subscription.

The Checkout Session metadata helps Revenue Linter tie acquisition context to the first checkout. The Subscription metadata helps that context stay available during later billing-state scans.

await stripe.checkout.sessions.create({
  mode: "subscription",
  customer: stripeCustomerId,
  line_items: [{ price: priceId, quantity: 1 }],
  success_url: successUrl,
  cancel_url: cancelUrl,
  metadata: {
    appUserId: user.id,
    utm_source: attribution.utmSource,
    utm_medium: attribution.utmMedium,
    utm_campaign: attribution.utmCampaign,
    utm_content: attribution.utmContent,
    utm_term: attribution.utmTerm,
    landing_page: attribution.landingPage,
    referrer: attribution.referrer,
    signup_source: attribution.signupSource
  },
  subscription_data: {
    metadata: {
      appUserId: user.id,
      utm_source: attribution.utmSource,
      utm_medium: attribution.utmMedium,
      utm_campaign: attribution.utmCampaign,
      landing_page: attribution.landingPage,
      signup_source: attribution.signupSource
    }
  }
});

Customer metadata

Keep the stable app identity on the Stripe Customer.

Customer metadata is useful when a workspace has subscriptions or payments that are missing Checkout Session metadata.

await stripe.customers.update(stripeCustomerId, {
  metadata: {
    appUserId: user.id,
    signup_source: attribution.signupSource,
    first_utm_source: attribution.utmSource,
    first_utm_campaign: attribution.utmCampaign
  }
});

One-time payments

Use PaymentIntent metadata for non-subscription revenue.

Revenue Expansion currently focuses on active subscriptions, but consistent PaymentIntent metadata helps later reconciliation and campaign cohorting.

await stripe.paymentIntents.create({
  amount: amountCents,
  currency: "usd",
  customer: stripeCustomerId,
  metadata: {
    appUserId: user.id,
    utm_source: attribution.utmSource,
    utm_campaign: attribution.utmCampaign,
    landing_page: attribution.landingPage
  }
});

How Revenue Linter uses it

Campaign cohorts

Groups active subscription MRR and signal counts by UTM source and campaign when metadata exists.

Silent churn context

Shows which acquisition source produced active-billing accounts with no recent app or product usage.

Expansion exports

Adds attribution columns to the CSV export for team-reviewed customer-success or upgrade follow-up.