rabolic.purchase()
Revenue you can trust, with the channel that earned it.
Only your server and your payment provider can report a sale, so a page view can’t fake one. Every purchase lands on the person who made it, and Rabolic credits it to their first or their last visit.
- Verified by your server
- Converted at the day’s rate
- First and last touch
Net revenue
$12,480
Refunds
$310
Paying users
102
Revenue attribution
First touchLast touch- Organic Search41$4,920
- Email28$3,310
- Paid19$2,150
- Direct14$1,640
- Direct37$4,410
- Email31$3,690
- Organic Search22$2,580
- Paid12$1,340
$purchase · $renewal · $refund
Two ways in, both verified.
@rabolic/node
From your server
Call purchase(), renewal() or refund() with the amount, currency and your transaction id. These events need a secret key, which never ships in a browser or an app.
Dodo Payments
From Dodo Payments
Connect Dodo Payments to a project with its webhook secret. Successful payments and refunds arrive as $purchase and $refund events on the same pipeline.
Dodo Payments is the one payment provider you can connect. Payments taken anywhere else, including Stripe and app stores, can be sent from your server with purchase().
Transactions
@rabolic/nodeDodo Payments- Pro, yearlyserver · purchase() · usr_8f2k1x9q$89.00
- Pro, monthlydodo · payment.succeeded · usr_3c7w0pb2€79.00$91.64€79.00 at Nov 6 rate
- Starter, monthlydodo · refund.succeeded · usr_q81zt5maRefunded$29.00
- $purchase rb_pub_…Refused: revenue needs a secret key
Project currency: USD. Originals are kept with each transaction.
@rabolic/node
A few lines on your server.
Send the sale where you already confirm it: after the payment provider says yes. Or connect Dodo Payments and put the user id in the checkout metadata.
purchase(),renewal()andrefund()need a secret key- Kept once per transaction id, however often it is sent
- Converted at the exchange rate of the day of the sale
- The original amount and currency are kept
// Verified revenue: only a secret key can send $purchase
await rabolic.purchase({
userId: 'usr_8f2k1x9q',
amount: 89,
currency: 'USD',
transactionId: payment.id,
product: 'Pro, yearly',
})first_touch · last_touch
Which visit earned the sale?
Rabolic follows each buyer back through their sessions. First touch credits the channel that first brought them; last touch credits the visit just before they paid. The Revenue page shows both.
Maya Chen
usr_8f2k1x9q
Oct 2
Organic Search
/blog/retention
Oct 9
Email
/pricing
Oct 14
Direct
Paywall
Each purchase is credited to one channel in each model.
Organic Search gets the $89.00. The buyer’s first session ever.
Direct gets the $89.00. Their last session before the purchase.
- One purchase, one channel
- In each model, a purchase is credited in full to one channel. Nothing is split or counted twice.
- 90 days back
- Sessions are looked for up to 90 days before the date range. A purchase with none is credited to Direct.
- Across devices
- The buyer’s sessions on the web and in your apps all count, once identify() has linked them.
the revenue page
Every number, defined.
All in the project’s currency, each against the period before, and all from verified revenue only.
- Gross revenue
- Verified purchases and renewals, before refunds.
- Net revenue
- Gross minus refunds. Store fees are not deducted.
- Refunds
- Counted on the day of the refund.
- Purchases and order value
- Purchases and renewals, and gross revenue per purchase.
- Paying users
- People with at least one verified purchase or renewal.
- MRR
- Renewals in the last 30 days, as an approximation of monthly recurring revenue.
- Revenue per user
- Gross revenue divided by unique users in the period.
- By platform and provider
- Where each purchase happened, and which source reported it.
- Lifetime value by first source
- Revenue per paying customer, by the channel that first brought them.
revenue faq
Revenue analytics, answered.
Why does revenue have to come from my server?
So the numbers can be trusted. $purchase, $renewal and $refund are only accepted with a secret key, from @rabolic/node or the HTTP API, or from a connected Dodo Payments account. Anyone can read a publishable key from your site or app, so it can’t report revenue.
Which payment providers can I connect?
Dodo Payments. Payments from any other provider, including Stripe and in-app purchases, can be sent from your server with purchase(), renewal() and refund() in @rabolic/node.
How does a payment find the right person?
Your server names the user id when it calls purchase(). For Dodo Payments, add checkoutMetadata({ userId }) from @rabolic/node to the checkout session, or the anonymous id before someone has an account. Without either, the payment is stored under the Dodo customer until that customer is identified.
How are other currencies handled?
Each purchase is converted into the project’s currency at the exchange rate of the day it happened, using the European Central Bank’s daily reference rates. The original amount and currency are kept. Organization totals are converted into the organization’s currency the same way, day by day.
What is the difference between first touch and last touch?
First touch credits a purchase to the channel of the buyer’s first session. Last touch credits it to their last session before the purchase. Each purchase is credited to one channel in each model, never split or counted twice.
How far back does attribution look?
Up to 90 days before the start of the date range. A purchase with no session in that time is credited to Direct.
Can a payment be counted twice?
No. Revenue is recorded once per provider and transaction id, so a webhook delivered twice or a retried request from your server is kept once. And a project has one revenue source: once Dodo Payments is connected, its webhooks are the revenue, and purchase() calls from your server stay as events for funnels and journeys without adding revenue.
Know which channel pays for itself.
Start a 3-day trial without a card. It begins with your first event, so you can set up the SDKs first.
- 1
Create a project
Sign up, name your project, and copy its publishable key.
- 2
Add an SDK
Web, React Native, Flutter or Node.js, or the HTTP API. Or run npx rabolic init.
- 3
Watch the first event arrive
It shows in live events within seconds, and your trial starts then.