Revenue & Stripe

Connect Stripe with a read-only key to see MRR, ARR and churn, and to know exactly which of your tracked people upgraded, to which plan, and their lifetime value.

Connect Stripe and OakData turns your subscription data into revenue analytics — MRR, ARR, churn and ARPU on a dedicated Revenue dashboard — and links each paying customer back to the person who visited your site, so you can see who upgraded, to which plan, and their lifetime value, right on their profile in People.

The connection uses a read-only restricted API key. OakData can only read your customers, subscriptions and charges — it can never create charges, issue refunds, or change anything in your Stripe account. There are no webhooks for you to configure: OakData backfills on connect and refreshes whenever you open the Revenue dashboard.

1. Create a read-only key

Open Stripe's Create restricted key form — the name (OakData) and the read-only permissions are already filled in, so you just click Create key. It grants Read access to:

ResourceTypeDescription
CustomersReadEmails, names and metadata used to match people.
SubscriptionsReadPlans, status and amounts — the basis for MRR/ARR.
ProductsReadPlan names shown on the dashboard and profiles.
Charges & refundsReadOne-off payments and refunds for lifetime value.
InvoicesReadSubscription billing history.
Checkout SessionsReadReads oak_distinct_id metadata for attribution.
Payment IntentsReadOne-off payment attribution and status.
AccountReadThe connected account's business name and currency.

Copy the key — it starts with rk_live_ (or rk_test_ in test mode).

Read-only and revocable

A restricted key with only Read scopes can't move money or modify your account. To disconnect for good, delete the key on Stripe's API keys page — OakData stores it encrypted at rest and never exposes it again.

2. Paste it into OakData

Go to Project → Settings → Stripe revenue, paste the rk_… key, and click Connect Stripe. OakData validates the key, pulls in your customers, subscriptions and charges, and computes MRR. Open the Revenue tab to see it.

3. Attribute revenue to the right person

To link a Stripe customer to a tracked visitor, OakData resolves in this order:

MethodTypeDescription
oak_distinct_idmetadataMost precise, and works even for anonymous visitors. Put the current visitor id (oak.getDistinctId()) into the Stripe object's metadata at checkout.
oak_user_idmetadataYour own user id — the same value you pass to oak.identify(). Use this when checkout happens server-side away from the browser.
emailfallbackIf no metadata is present, OakData matches the Stripe customer email against the emails your visitors were identified with.

Billing email ≠ login email

People often check out with a different email than the one they signed up with, so email matching alone misses them. Whenever you can, pass oak_distinct_id or oak_user_idin metadata — it's exact, and it captures anonymous upgrades that email never would.

The visitor id lives in the oak_did cookie (set by the tracking SDK) and is also available client-side as oak.getDistinctId(). Read it when you create the checkout and attach it as metadata:

import { cookies } from 'next/headers'
import Stripe from 'stripe'

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!)

export async function POST(req: Request) {
  const oakId = (await cookies()).get('oak_did')?.value

  const session = await stripe.checkout.sessions.create({
    mode: 'subscription',
    line_items: [{ price: 'price_123', quantity: 1 }],
    success_url: 'https://example.com/thanks',
    // Copy the id onto the subscription (and customer) so OakData's
    // sync sees it on the persisted objects, not just the session.
    metadata: { oak_distinct_id: oakId ?? '' },
    subscription_data: { metadata: { oak_distinct_id: oakId ?? '' } },
  })

  return Response.json({ url: session.url })
}

Put metadata on the persistent object

OakData syncs Customers and Subscriptions, so attach the id to subscription_data.metadata or the Customer's metadata— not only the Checkout Session, which the sync doesn't page through. client_reference_id on Payment Links is copied onto the resulting subscription automatically.

Email fallback

Even without metadata, identified people are matched by email. Make sure you call oak.identify() with an emailtrait so there's something to match on:

client
ts
oak.identify('user_123', { email: 'sam@example.com', name: 'Sam Rivera' })

What you get

WhereTypeDescription
Revenue dashboardtabMRR, ARR, active subscribers, ARPU, an MRR trend, revenue by plan, and your top customers.
People listpillA plan + MRR pill on each paying person, plus a “Paying customers” filter.
Person profilepanelPlan, MRR, lifetime value and subscription status on the visitor you already know.

FAQ

QuestionTypeDescription
How fresh is the data?OakData backfills immediately on connect and refreshes each time you open the Revenue dashboard. Use “Re-sync” in Settings to force a refresh on demand.
How is MRR calculated?Active and past-due subscriptions, normalized to a monthly amount (annual ÷12, quarterly ÷3, weekly ×4.33). ARR is MRR ×12.
Test mode?Yes — connect an rk_test_ key to preview with your Stripe test data before going live.