Build a ChartMogul alternative

Build a ChartMogul alternative from an invoice CSV, monthly MRR, and a churn list. The card lists $69 to $119 a month. Live billing sync stays later.

  • getting-started
  • vibe-coding
  • scope

You can build a ChartMogul alternative from an invoice CSV, a monthly MRR number, and a churn list. ChartMogul is that product. The catalog line is “Invoices in. MRR and churn out.”

The card lists $69 to $119 a month. ChartMogul’s pricing page lists Starter at $69 a month through Pro at $119 a month, billed monthly. Annual Starter is $57 and annual Pro is $99. The card leaves out the free plan, which covers up to $10,000 of MRR, and Enterprise from $19,900 a year. The first estimate is 10 hours. The verdict is “MRR you can add up”.

Last time I wrote about building a Vimeo alternative. That was a teardown. This one is a regular backlog topic. Live billing sync stays on the skip row.

Build a ChartMogul alternative from one CSV

The ChartMogul page splits the work into three rows.

The first row is 10 hours. Invoice import, MRR, and a churn list. You bring a file. The month has a number. The customers who stopped are listed.

The second row is 3 days. Expansion, a month compare, and a second source CSV. A chart of October against November can wait until November’s number already matches the file.

The third row is 1 month and up. Live billing sync, a CRM, and a warehouse export. The table labels that row as the part you should skip.

If you tell an agent to “clone ChartMogul”, it aims at the third row. Copy the prompt, then pin it to the first one.

Store Customer, Invoice, Plan, and MonthSnapshot. The card names all four. For these 10 hours, all four exist. The customer is the name on the invoice. The plan carries the interval in months. The invoice is the amount and the period. The snapshot is that month’s MRR and the customer ids in it, so the next import can see who left.

A customer is a name, unique on your account. A plan is a name and an interval, 1 for monthly and 12 for annual. An invoice is an amount in cents, a plan, and a start and end date. A month snapshot is the total for one calendar month and the customers who contributed.

The audience is a founder tracking subscription revenue from one billing export. The goal on the card is to import invoices, see MRR and churn, and know which customers moved. The same v1 also stands in for Baremetrics and Maxio. The card lists both and does not give them prices.

A ledger with invoices and a profit figure is Xero at $27 to $97 a month. A shorter invoice loop is FreshBooks at $23 to $60 a month, in Vibe code your own FreshBooks. Named events and a funnel are Mixpanel at $140 to $2,289 a month, in Vibe code your own Mixpanel. Xero keeps the books. Mixpanel counts what people did in the product. This file is the billing export you already downloaded.

A sales pipeline is HubSpot CRM at $20 to $150 a person a month, in Build a HubSpot alternative. The non-goal on the ChartMogul card says the clone is not that pipeline, and it is not a live billing connector.

The guardrail is the rule you paste into the prompt. Store amounts as integer cents. Compute MRR on the server from imported invoices. Reject a CSV that fails validation without writing a partial import.

How a ChartMogul alternative adds up MRR

Mira closes November on November 7, 2026. The file is invoices-nov.csv. Two rows are valid.

Northwind Studio is on Pro, interval 1, amount 4900 cents, period November 1 through November 30. Harbor Mail is on Annual, interval 12, amount 58800 cents, period November 1, 2026 through October 31, 2027. Pine and Co paid 2900 cents in October and has no November row.

November MRR is 4900 plus 4900, which is 9800 cents, $98. Harbor’s $588 becomes $49 because you divide by 12. Pine and Co is the churn list, at the $29 from the October snapshot.

ChartMogul’s MRR article says a monthly plan contributes the amount paid each month, and any other plan is normalized from the invoice amount and the billing interval. Their line item article says subscription and trial lines count, one-time charges do not, and tax is removed before the division. Their proration writeup uses this shape. Take the amount in cents, subtract tax, multiply by the ratio that turns the interval into a month, then multiply by a prorate factor. The factor is 1 when the line is not prorated. A $90 charge for 3 months is $30 of MRR in that page’s example.

The 10-hour clone keeps that non-prorated case. Cents divided by the interval. There is no tax column, so the cents in the file should already exclude tax. There is no refund column either. The MRR article says refunds change MRR only for Stripe, and other billing sources leave the number alone. The CSV cannot see that setting. If a charge was refunded and you do not want it in the month, leave the row out.

Their invoice handling article says the default is to count a new subscriber when the first invoice is fully paid. Issued, or partially paid, are the other choices. The clone does not know paid from open. You make that call before the row goes in the file.

A second Harbor row that also covers November is an error. One covering invoice per customer per month. Their line item article lists proration types for a mid-month change, including differential and full. The clone has no proration column. Resolve a plan change in the file, or leave it for the month row.

A third row, Lumen Co, has a start and a blank end. Import stays off. Northwind, Harbor, and the October snapshot are not touched.

Your browser talks to one Astro app. Node.js plus Astro is the default. Use TanStack Start if React is your weekday language. The capability line on the card is Astro, HTMX, and D1. Customers, plans, invoices, and the November snapshot live in D1. Nothing in this row calls Stripe.

Every query is scoped to Mira. A guessed customer id from another account returns an empty page.

Screens of a ChartMogul alternative

v1 needs the import, the month, and one customer. Expansion and a second file are the 3-day row.

The import

Mira has invoices-nov.csv open. Two rows preview clean. Lumen Co is marked bad because the period end is empty. Import is off until that row is gone. The note on the screen says a bad file writes nothing.

WIREFRAME · IMPORT invoices-nov.csv · November 2026 Northwind · Pro · 4900 · ok Harbor Mail · Annual · 58800 · ok Lumen Co · end date blank · bad A bad row blocks the whole file Import off Nothing is written while Lumen is in the file
Lumen Co is missing an end date, so the two good rows stay unwritten.

The month

After a clean file, November reads $98. Northwind and Harbor are active. Pine and Co is the churn list at $29. Mira does not type the total. It is the sum of the stored rows whose period covers November, with Harbor divided by 12.

WIREFRAME · NOVEMBER MRR · $98 · from stored cents Northwind Studio · active · $49 Harbor Mail · active · $49 Annual 58800 cents, divided by 12 Churn · Pine and Co · $29 Expansion and a month chart wait The total is not typed on this page
November is $98. Pine and Co is the only name on the churn list.

The customer

Harbor’s page shows one invoice, the annual period, and the $49 that landed in November. The status is active because that period covers the month. Pine’s page would show the October invoice and a churned status, with no November row.

WIREFRAME · CUSTOMER Harbor Mail · active Plan · Annual · interval 12 Invoice · 58800 cents Nov 1, 2026 to Oct 31, 2027 November share · $49 One invoice explains the status
The $49 is the annual invoice divided by 12, not a second charge.

How an invoice CSV becomes a month

Mira drops the bad row and imports. The server checks every remaining row for a customer, a plan, an interval, an integer cent amount, and two dates. Then it writes customers, plans, and invoices in one transaction. If the write fails halfway, the month still shows October.

Node.js plus Astro reads that transaction back and builds the November snapshot. A customer is in the month when one invoice period covers it. MRR for that customer is the cents divided by the interval. The snapshot stores $98 and the two ids. Pine and Co is on the October snapshot and missing from this one, so the churn list is that name and $29.

Next month’s import uses this snapshot the same way. Expansion, a side-by-side of the two months, and a second billing CSV are the 3-day row. A Stripe connection, proration types, and a warehouse export are the month row.

MIRA UPLOADS THE FILE invoices-nov.csv · preview first REJECT OR WRITE Blank end date writes nothing ONE TRANSACTION Customers, plans, invoices, then stop NOVEMBER SNAPSHOT $98 · Northwind and Harbor Churn · Pine and Co · $29
Ten hours ends when November reads $98 and the churn list names Pine and Co.
MIRA'S BROWSER Preview the CSV, then the month ASTRO APP Validate, write once, divide by interval D1 Customers, invoices, plans, snapshot LATER, THEN SKIP Live billing sync Proration, tax, refunds A CRM and a warehouse export No connector in the 10-hour row
The CSV and D1 are the v1. The dashed box is the billing connection the card says to skip.

Start with the first row

Go to Build your own ChartMogul. Copy the Astro prompt, or TanStack Start if that is what you write.

Tell the agent the first estimate only. Invoice import, MRR, and a churn list. Ten hours.

Import a clean invoices-nov.csv, confirm November reads $98, and confirm Pine and Co is the only churn row. Paste the all-or-nothing rule from How to write a coding agent prompt, and keep the three rows in How to scope a SaaS clone. If you need Stripe, proration, or a CRM, keep the plan you already pay for that part.

Keep reading

Read all articles →