Guides

How to calculate AI margin per user in a RevenueCat app

In short: AI margin per user is what a user paid you, net of store fees and tax, minus what their AI usage cost. The hard part isn't the arithmetic. It's using the same user ID in your AI tracking and in RevenueCat, and counting revenue the way it really arrives.

RevenueCat tells you who paid. Your AI provider tells you how many tokens you used. Neither knows about the other, so margin per user has to be built by joining them.

1. Use the RevenueCat user ID everywhere

Every join below depends on one value: the RevenueCat app user ID. Your backend must report each AI call under that exact ID.

Best option: log users into RevenueCat with your own user ID (Purchases.logIn(yourUserId)). Then the RevenueCat ID is the ID your backend already has from your own auth, and nothing extra needs to travel.

If you use RevenueCat's anonymous IDs (they start with $RCAnonymousID:), your backend doesn't know the value. Send it from the app with each AI request, for example in a header:

PlatformGet the app user ID
iOS (Swift)Purchases.shared.appUserID
Android (Kotlin)Purchases.sharedInstance.appUserID
React Nativeawait Purchases.getAppUserID()
Flutterawait Purchases.appUserID
// backend: use the ID you were sent (or better, the one tied to your auth)
const userId = req.headers["x-rc-app-user-id"];

A header sent by the app can be faked, so for money decisions prefer an ID you derive from your own authenticated session. For measuring margin, a header is fine.

Aliases: when a user goes from anonymous to logged in, RevenueCat merges the IDs and lists the old ones as aliases. Your join should treat all of a user's aliases as one person, otherwise their cost and their revenue land on different IDs.

2. Get revenue from RevenueCat

Add a webhook (Integrations → Webhooks) that points at your own endpoint. Each event describes one thing that happened to a subscription. The ones that matter for revenue:

EventWhat it means for margin
INITIAL_PURCHASE (trial)A trial starts: AI cost begins, revenue is $0
INITIAL_PURCHASE (paid)First payment: add net revenue
RENEWALAnother payment: add net revenue. A trial conversion is marked on the first one
CANCELLATIONAuto-renew turned off, or a refund (negative price): subtract refunds
EXPIRATIONAccess ended: no more revenue, but cost may continue if you don't cut them off
PRODUCT_CHANGEPlan changed: attribute future cost to the new plan

Two practical rules: de-duplicate on the event ID (RevenueCat retries deliveries), and ignore sandbox events in production reporting.

3. Use net revenue, not the sticker price

The App Store and Google Play keep a cut, and tax is collected on top. Each event carries the price and both percentages, so:

net_revenue = price_usd × (1 − tax_percentage − commission_percentage)

On a $9.99 plan a 15% store cut and some tax can leave you with well under $8. Measuring margin against $9.99 overstates it for every user.

4. Compute margin, and watch for these traps

margin = net_revenue − ai_cost     (same user, same time window)

The shortcut

FiscaLLM does the join for you. One line reports AI cost under the user's ID, a RevenueCat webhook reports payments, and you get margin per user, per plan and per trial cohort, with alerts when someone crosses a budget. Aliases, net revenue, de-duplication and refunds are handled. Annual plans are counted when the payment arrives, so use a 90-day view for them.

meter.trackOpenAI(res, { userId, feature: "chat" });   // userId = RevenueCat app user ID
// RevenueCat → Integrations → Webhooks → paste the URL and authorization value from your Setup page

It's free and open source. Open the demo dashboard (no sign-up), read how it works, or start free. Per-provider details: OpenAI and Anthropic Claude.

Questions

Does RevenueCat show AI cost?

No. It reports revenue and subscription state only, so AI cost has to come from your own backend and be joined by user ID.

What if I don't use RevenueCat?

The same method works with any billing system: report each payment, refund and cancellation under the same user ID your AI calls use.

Which user ID should I use?

The RevenueCat app user ID. If you log users in with your own ID, that is your own ID.