Track

Revenue

Record purchases with a revenue property, or connect Stripe to import payments.

There are two ways to get revenue into AnyAnalytics: add a revenue property to your own events, or connect your Stripe account so payments and refunds are recorded for you. Either way, revenue shows on the Overview next to the visitors and players who brought it.

The revenue property

Any event with a numeric revenue property counts as revenue. Add an optional currency with the three-letter ISO code.

shop.jsjs
// Any event with a numeric "revenue" property counts as revenue
analytics.track("purchase_completed", {
  item: "gem_pack_s",
  revenue: 4.99,
  currency: "USD",
});
  • Send the amount in major units: 4.99 dollars, not 499 cents.
  • Numbers and numeric strings ("4.99") both work. Anything else counts as zero.
  • The event name is up to you. purchase_completed, order_paid or subscription_renewed all count.
  • Send revenue from wherever the payment is confirmed. For real money, that's usually your server, so a player can't fake a purchase.

Where revenue shows up

When the period you're looking at has revenue, the Overview shows revenue, conversion rate (the share of people who paid) and revenue per person to its headline numbers. Revenue is credited to the source, entry page, country and device of the visit that brought the person, so the breakdowns show which channels make money, not just traffic. The Journey tab under Goals lists the paying customers and how they first found you.

Goals

Each goal on the Overview shows the revenue of the events that match it. Make your purchase event a goal to see its completions, conversion rate and revenue side by side.

Several currencies

Amounts in different currencies are never added together. Each report picks one currency, the one used by most revenue events in the period, and totals that. Revenue in any other currency is listed separately next to the total, marked as not included.

Events without a currency are counted in the report's currency. If you only ever sell in one currency you can leave it out; if you sell in several, always send it.

Refunds

Refunds recorded by the Stripe integration appear as dashed bars on top of the revenue chart. They're shown alongside revenue rather than subtracted from it, so you can see both.

Connect Stripe

If you take payments with Stripe, connect it to record real payments and refunds without sending any events yourself. It's included on every plan. Only owners and admins of a project can connect it.

  1. Add a webhook endpoint in Stripe

    In your project, open Settings → Revenue and copy the webhook URL. In Stripe, open Developers → Webhooks → Add destination, paste the URL and select these events:

    • checkout.session.completed
    • checkout.session.async_payment_succeeded
    • invoice.paid
    • charge.refunded
  2. Paste the signing secret

    Stripe shows a signing secret for the new endpoint, starting with whsec_. Paste it in Settings → Revenue and click Connect. It's stored encrypted and never shown again; every delivery is checked against it.

  3. Pass the visitor into Checkout

    So that each payment is credited to the right visitor, send their AnyAnalytics ids to your checkout endpoint and put them in the Checkout Session's metadata.

checkout-button.jsjs
// In the browser, when the visitor clicks "Buy" (script tag: window.anyanalytics,
// npm SDK: the analytics instance you initialized).
const res = await fetch("/api/checkout", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    priceId: "price_123",
    visitorId: anyanalytics.distinctId,
    sessionId: anyanalytics.sessionId,
  }),
});
location.href = (await res.json()).url;
api/checkout.jsjs
// On your server (Node, stripe package). The ids also go on the payment /
// subscription so refunds and renewals are attributed to the same visitor.
const metadata = {
  anyanalytics_visitor_id: body.visitorId ?? "",
  anyanalytics_session_id: body.sessionId ?? "",
};
const session = await stripe.checkout.sessions.create({
  mode: "payment", // or "subscription"
  line_items: [{ price: body.priceId, quantity: 1 }],
  success_url: "https://example.com/thanks",
  client_reference_id: body.visitorId,
  metadata,
  payment_intent_data: { metadata }, // mode "payment"
  // subscription_data: { metadata }, // mode "subscription"
});
return { url: session.url };

The metadata keys are anyanalytics_visitor_id and anyanalytics_session_id. If there's no visitor id in the metadata, the Checkout Session's client_reference_id is used instead.

Test it

Use Send test event on the endpoint in Stripe. The Revenue settings show when the last delivery arrived, and the last error if one was rejected.

What's recorded

  • Paid one-time Checkout payments, as a $payment event with revenue and currency. Payments by bank debit count once they succeed.
  • Subscription invoices, the first one and every renewal. Invoices sent through Stripe Invoicing that aren't part of a subscription are not counted.
  • Refunds, as a $refund event for the amount refunded. Partial refunds are recorded one by one.
  • Stripe sometimes delivers the same event twice. Each one is recorded once.

How payments are matched to visitors

  • A payment is credited to the visitor named in its metadata. It takes that visitor's device, location and session, so it lands on the source that brought them.
  • Renewals and refunds are matched through the ids on the payment or subscription metadata (the server snippet above sets them), or through the Stripe customer remembered from their first Checkout.
  • Payments that can't be matched still count, as a person of their own.

Disconnecting Stripe stops new payments and refunds from being recorded. Revenue already recorded stays.

See also