Normalized MRR and ARR
Weekly, monthly, quarterly, semiannual and annual compared after normalization. Moving 99 a month to 1,800 a year is 51 of expansion, not 1,701.
DuckLedger joins revenue, cost and behavior in one ledger. MRR, cohorts and churn from 7 gateways and the app stores; cloud, AI, WhatsApp and hosting with an owner; screens, friction and campaigns per person. And the answer that only exists once it all closes: margin by product, by customer, by user and by campaign.
Multi-product · RBAC · Encrypted secrets · No spreadsheet archaeology
Sample · current month
MRR
R$ 248.4k
Gross margin
63.3%
Cost / user
R$ 3.12
LTV:CAC
4.1×
Full revenue metrics
MRR, ARR, waterfall, NRR, GRR, cohorts and conversion funnel.
Every cost has an owner
Cloud, AI and expenses allocated to the product that caused them.
Margin per user
Revenue minus direct cost, down to the person and the session.
Behavior with revenue
Screens, friction, retention and campaigns tied to what each person pays.
Three short videos: the path from money to margin per person, what in-product behavior says about retention and campaigns, and how a cloud bill becomes cost per request.
Asaas, Stripe, Pagar.me, Mercado Pago and the app stores land in one ledger — Pix, cards and in-app, with fees and refunds kept apart from gross.
A revenue tool knows what came in. A FinOps tool knows what went out. Some already join cloud cost with usage billing — but not Asaas, Pix, stores and AI on one Brazilian founder P&L. These are DuckLedger’s questions.
Revenue tools stop at stage 3. Cloud FinOps starts at 4; large stacks already import usage-billing revenue, but they do not cover Asaas, Pix, or a Brazilian founder. “Is this customer profitable?” lives at the joint — same product, same period, same currency.
Charge
Subscription
Analytics
Cost
Allocation
Profit
MRR, churn, cohorts
cloud cost by tag
crosses the joint
The gateway moves the money at stage 1. DuckLedger explains the five that follow.
Not a pretty MRR chart on top of a CSV. A ledger of movements, daily snapshots and outcomes written when they happen — because a canceled subscription no longer remembers what it was worth.
Weekly, monthly, quarterly, semiannual and annual compared after normalization. Moving 99 a month to 1,800 a year is 51 of expansion, not 1,701.
New, expansion, reactivation, contraction and churn — with voluntary churn separated from involuntary by the status the subscription lapsed from.
Cohort retention, ARPU, average lifetime, and NRR/GRR anchored to the snapshot the month opened on.
Outcomes written once and never recomputed. Rate over resolved, with the still-open population always shown beside it.
RevenueCat covers Apple, Google and web at once; App Store and Play also connect directly. Store commission and refunds kept apart from gross.
Asaas, Stripe, Pagar.me, Paddle, Iugu, Mercado Pago and AbacatePay: Pix, boleto, cards and subscriptions, with idempotent webhooks and several gateways synced side by side.
Customer attributes, saved segments, and a revenue forecast built from observed movements.
Every payment resolved to the product that earned it — never “somewhere in the gateway.”
A cost with no product never becomes margin. DuckLedger imports spend where it originates, attributes it to a workspace, and forces a question accounting never asks: does this serve a customer, buy one, or neither?
Vercel exact by service and project; Supabase and Hostinger estimated from the plan and labelled as such. Alerts when a renewal gets dearer.
Each message priced from Meta’s rate of the day, by category and country — and tied to the person who received it.
Automatic sync of spend by service, written as an expense on its competence date and allocated by product.
OpenAI, Anthropic, OpenRouter, Gemini and more, with a daily sync and attribution by project, key and workspace.
Manual, recurring and CSV-imported, with supplier, category and competence date.
Cost of revenue, acquisition or overhead. Every category starts as overhead, so an unclassified one never silently inflates margin or CAC.
Shared cost stays at the organization; each workspace’s P&L stays clean and comparable.
An auditable formula engine: total cost over active users, operations or requests — whichever metric you define.
Six deterministic rules point at what to cut: an idle subscription, an expensive model for the task, an unused service. Each with the amount at stake.
The cost the SDK measured is compared with the provider’s bill. The difference shows; the two are never added.
A revenue LTV tells you what a customer will pay. Only LTV on margin tells you what you keep — the one version comparable to what acquiring them cost. Four figures no revenue-only tool can produce.
gross margin = (revenue − cost of revenue) / revenue CAC = acquisition spend / new customers LTV (margin) = ARPU × average lifetime × gross margin LTV:CAC = LTV (margin) / CAC payback = CAC / (ARPU × gross margin)
A month that acquired nobody does not have a CAC of zero — it has no CAC. A negative margin has no payback period. The figure comes back null instead of lying.

Everyone charts revenue retention by cohort. Here the cohort accumulates gross profit until it covers what acquiring it cost — and the month that happens has a name.
Losing a high-margin customer and a negative-margin one are not the same event. One of them improves the company.
The margin rate comes from the P&L; recurring revenue lives on its own basis. Carrying the rate into MRR is standard practice — adding cash revenue to MRR is the error this separation exists to prevent.
Average cost per active user is a division, not a measurement. Instrument what the product actually does, and every model call, job and conversation gets an owner, a session, a currency and an amount.
One ingest key and one package. Batching, retries and idempotency on the event ID.
Usage already lives in your tables: one read-only view and a scheduled query.
Already-standardized events import directly with host, project and a personal key.
await usage.withTrace(
{
kind: 'conversation',
name: 'Support chat',
subject: user.id,
},
async (trace) => {
trace.step('retrieveContext');
usage.track({
type: 'ai.tokens_spent',
data: {
model: 'gpt-4o',
prompt_tokens: 1200,
completion_tokens: 400,
},
});
},
);Tokens with no cost attached are priced from public list rates and marked estimated. Pass a measured cost and it replaces the estimate.

Conversation, checkout or job: every step, provider and service hop on one row, with duration and cost.
What the provider charged and what the price catalog computed carry different labels on the same screen.
A trace that burned USD on a model and BRL on a gateway fee cost two things. Picking an exchange rate to merge them is your decision, not the cell’s.
Your app’s internal ID becomes the identity; the e-mail links the person to the customer on its own, and one account can pay for many users without multiplying the revenue.
A live panel of active people, from where and on what — with real-time cost and revenue and a forecast for the month.
Analytics tools show clicks. DuckLedger ties every screen, funnel and campaign to the revenue and cost of the people who went through it. The question stops being “how many used it” and becomes “do the people who use this stay and make money?”.
People, views, sessions, median time, conversion and D7/D30 return per screen — with ids collapsed into /orders/:id.
Errors, failed actions, rage clicks, dead clicks, abandoned forms and slow completions, in one score that always explains itself.
Screens, actions and features in sequence. The step with the biggest drop is highlighted.
D1, D7 and D30 over people who have had time to return, weekly cohorts and DAU/MAU stickiness.
Sessions, active days and main screen next to each person’s revenue, cost and contribution.
First- and last-touch UTMs through to payment: visitors, sign-ups, activated, paying, CAC, ROAS and result.
People who used each screen or feature early versus those who did not: retention, paying share and contribution.
Connect PostHog and every screen links to its heatmap and recordings, without a second tool to babysit.
The tracker posts to a route of your app, which attaches the signed-in user. A page cannot pretend to be someone else.
Paths without query strings, ids collapsed to :id, elements named without their text and no form contents read.
The source stays on the device: someone who came from an ad and signed up days later is still credited to that ad.
An assistant that reads your ledger — revenue, cost, usage and behavior — and answers as a report, with tables and charts. It also sets things up: it creates and validates keys and explains which SDK to use.
Why did NutriOS margin drop in September?
✦ Duck CFO
AI cost per user rose 38% after support chat moved to a larger model, while revenue held flat. Moving short conversations back to the previous model would recover about $2.1k a month.
This is not modesty — it is what separates a decision dashboard from a decorative one. When the basis is missing, DuckLedger says it is missing.
Spending R$ 3,000 and acquiring nobody is not free acquisition. With no basis the answer is null, and the screen says what still needs connecting.
A cost derived from list prices never dresses up as a measured one. The same holds for trace names inferred from the route.
Sandbox and production are filed under the environment the event carries, not the one the connection was set to.
Idempotent webhooks, store aliases resolved to a single customer, and instrumented cost reconciled against the invoice rather than added to it.
Compared by category, not by brand. Large FinOps already joins cloud cost with usage-billing revenue; DuckLedger joins Asaas, stores, cloud, AI and expenses on one P&L, in reais.
MRR, churn, cohorts
Apple and Google subscriptions
Pix, boleto and BR billing
Cloud cost by product
AI API cost
Margin and profit by product
LTV on gross profit
Cost and revenue per user
WhatsApp and hosting cost per person
Screens and friction tied to revenue
CAC and ROAS per campaign, on margin
Answer the same day
No six-week implementation. Wire the structure once, and the numbers compound on their own.
One organization, one workspace per product. Shared cost stays at the org; each product’s P&L is comparable from day one.
Asaas for Pix, boleto and cards; RevenueCat or the stores for in-app purchase. Backfill once, webhooks for the rest.
AWS, AI providers, WhatsApp, Vercel, Supabase, Hostinger and expenses. Classify each category as cost of revenue, acquisition or overhead.
Server SDK plus the browser tracker. From there, “what does this user cost, earn, where do they get stuck and where did they come from” has an answer with a name and a session.
One subscription per company, priced on how many customers you track. No per-seat charge, no cut of your revenue.
Para validar antes de pagar.
Free
Para quem já tem receita entrando.
R$99.90/month
Para operações com vários produtos.
R$299.90/month
On paid plans the card goes in now and the first charge lands after 14 days. Cancel before that and nothing is charged.
Hit the limit? Nothing is deleted — only new customer records pause until you change plan.
Connecting sources, classifying cost, splitting it per product and reading the number every month is work — and it is where most people stop. On the managed tiers that part is mine, not yours: you get the close and the decision it points to.
Um produto, a margem fechada todo mês.
R$2,500/month
For companies at R$ 20 mil a R$ 100 mil de MRR
6 month minimum term
Vários produtos, cada um com o seu P&L.
R$4,900/month
For companies at R$ 100 mil a R$ 400 mil de MRR
6 month minimum term
Implementation is inside the monthly fee, never billed separately. Above R$ 400k MRR, or for anything outside the scope above, the engagement is quoted.

An ingest key lives on your server and its scope is deliberately narrow: send events, read the meter catalog, register a missing type. Nothing else.
If you run digital products and the revenue answer lives in one tool, the cost in another, and the margin in none — that joint is what DuckLedger closes.
Already on the team? Sign in and pick up where you left off.