Revenue & retention
Report conversions and churn from your backend so your onboarding analytics show real money — what a trial is worth and which path pays off.
Onboarding analytics show you who activated. Connect revenue and you also see who paid: what a trial is worth, which onboarding path turns into paying customers, and whether those customers stick around.
You report billing events from your backend — a conversion, a renewal, a refund, a cancellation — using the same user id you already pass the browser SDK. Sunboard attributes the money to that user's onboarding journey.
It works with any billing setup. You call it from the code that already runs when a customer pays or cancels, so Stripe, Paddle, and your own invoicing all work the same way.
Set it up
Get a secret key
In your project dashboard, open Settings → Secret key and generate one. It's
shown once, so store it in a server-side environment variable such as
SUNBOARD_SECRET_KEY. Keep it on your server — never ship it to the browser.
Report billing from your backend
import { Sunboard } from "@sunboard/node";
const sunboard = new Sunboard({ secretKey: process.env.SUNBOARD_SECRET_KEY! });
// A trial converts to paid. Amounts are in the smallest currency unit (cents).
await sunboard.revenue({
userId: user.id,
amount: 4900,
currency: "usd",
idempotencyKey: invoice.id,
});
// A customer cancels or lapses.
await sunboard.churn({ userId: user.id });Pass the same userId you give the browser SDK so revenue lands on the right
onboarding journey.
Billing events
revenue() records money coming in; churn() records a customer leaving. The
event type defaults to conversion:
| Moment | Call |
|---|---|
| Trial converts to paid | revenue({ ..., type: "conversion" }) (default) |
| Subscription renews | revenue({ ..., type: "renewal" }) |
| Upgrade or add-on | revenue({ ..., type: "expansion" }) |
| Money refunded | revenue({ ..., amount: -4900, type: "refund" }) |
| Subscription cancels or lapses | churn({ userId }) |
Amounts are whole numbers in the smallest currency unit (cents for USD), with an
ISO currency. Refunds use a negative amount. churn() takes no amount — it just
marks the end of a customer's subscription.
Safe to retry
Pass an idempotencyKey (your invoice or charge id works well) and sending the
same event twice is ignored instead of counted twice.
You can also record product events from your backend with
sunboard.track({ userId, eventName }) — useful when the action that proves value
happens on your server instead of in the browser.
What you see
Once billing is flowing, your project dashboard and
sunboard analytics revenue show:
- Trial → paid conversion, overall and per onboarding path and segment
- What a trial is worth on average
- Revenue per activated user versus everyone else
- Time to paid — how long conversion takes
- Retention and churn by onboarding path
- Net revenue (refunds included) and lifetime value per customer
The /sunboard.analyze skill reads these too, so it can
prioritize fixes by revenue, not just by where users drop off.