How to Calculate MRR from Your Stripe Data
January 30, 2026
If you run a SaaS business on Stripe, you've probably noticed something frustrating: Stripe doesn't show you your MRR. You get gross volume, net volume, and a chart of successful payments — but not the single number every SaaS founder needs to know.
Calculating MRR from Stripe data is straightforward in theory, but the details trip people up. Annual subscriptions, trials, multi-item plans, and past_due statuses all need to be handled correctly. This guide walks through the exact methodology, including the edge cases.
What MRR actually measures
Monthly Recurring Revenue is the normalized monthly value of your active subscriptions. "Normalized" is the key word — a customer paying $1,200/year contributes $100/month to MRR, not $1,200 in the month they pay.
MRR tells you the predictable revenue run rate of your business at a point in time. It's not the same as monthly revenue (which includes one-time charges, overages, and timing effects from annual payments).
Step 1: Decide which subscriptions count
Not every Stripe subscription should contribute to MRR. Here's how to categorize each status:
| Status | Counts toward MRR? | Why |
|---|---|---|
active | Yes | Customer is paying |
past_due | Yes | Payment failed but subscription is still active — this is at-risk MRR |
trialing | No | Customer hasn't paid yet |
canceled | No | Subscription ended |
incomplete | No | Initial payment hasn't succeeded |
incomplete_expired | No | Setup window expired |
unpaid | No | All retry attempts exhausted |
paused | No | Temporarily suspended |
The past_due decision is worth discussing. Some teams exclude it because the payment failed. We recommend including it because the subscription is still active — Stripe is still retrying the payment, and the customer still has access. If you exclude past_due, your MRR will drop every time a credit card expires and bounce back when the retry succeeds, creating noise that doesn't reflect real business changes.
Step 2: Normalize to monthly amounts
Stripe subscriptions can bill on different intervals. To get MRR, every subscription needs to be expressed as a monthly amount.
The normalization formulas:
| Billing interval | Conversion |
|---|---|
| Monthly | Amount as-is |
| Yearly | Amount / 12 |
| Weekly | Amount x 4.33 |
| Daily | Amount x 30 |
| Every N months | Amount / N |
For multi-interval plans (e.g., "every 3 months"), divide by the interval count after converting. A subscription charging $90 every 3 months contributes $30/month to MRR.
Handling quantity-based pricing
If a subscription item has quantity > 1 (common with per-seat pricing), multiply the unit amount by the quantity before normalizing:
item_mrr = (unit_amount × quantity) → normalize to monthly
A plan priced at $10/seat/month with 5 seats contributes $50/month to MRR.
Multi-item subscriptions
A single Stripe subscription can contain multiple line items (e.g., a base plan plus an add-on). Sum the normalized monthly amount of each item:
subscription_mrr = sum(item_mrr for each item in subscription.items)
Step 3: Sum it up
Total MRR is the sum of all qualifying subscriptions:
MRR = Σ subscription_mrr
where status ∈ {active, past_due}
That's the core calculation. If you're pulling this from the Stripe API, you need the List Subscriptions endpoint with status set to active, then a separate call for past_due. For each subscription, iterate over subscription.items.data to get the unit amount, quantity, and price interval.
The edge cases
Coupons and discounts
Stripe applies coupons at the subscription or invoice level. If a subscription has a 20% coupon, the customer pays 80% of the list price. Whether you count MRR at list price or discounted price depends on your preference — but be consistent.
Most SaaS businesses use the discounted price for MRR because it reflects actual expected revenue. If you're using the Stripe API, the discount object on the subscription tells you what's applied.
Free trials
Subscriptions in trialing status should not contribute to MRR. They haven't paid yet, and some percentage will never convert. Counting trials inflates your MRR and gives you a false sense of progress.
Metered / usage-based billing
Strictly speaking, usage-based charges aren't recurring in a predictable way, so they don't belong in MRR. If you have a hybrid model (base subscription + metered overage), count only the base subscription portion.
Currency conversion
If you bill in multiple currencies, you'll need to convert everything to a single base currency for a meaningful MRR number. Use a consistent exchange rate — either a fixed monthly rate or the rate at subscription creation. Avoid using real-time rates, which add unnecessary volatility.
MRR movement categories
Once you can calculate MRR at a point in time, the next step is tracking how it changes. MRR movement breaks down into:
- New MRR — from subscriptions created this period
- Expansion MRR — existing customers upgrading or adding seats
- Contraction MRR — existing customers downgrading
- Churned MRR — from subscriptions that canceled this period
- Reactivation MRR — from previously canceled customers resubscribing
The formula:
MRR(end) = MRR(start) + New + Expansion + Reactivation - Contraction - Churned
Tracking these components tells you why MRR changed, not just that it did. A business growing MRR through new sales while hemorrhaging existing customers looks very different from one growing through expansion revenue.
Calculating MRR from the Stripe API
Here's the practical approach if you're building this yourself:
- Fetch all subscriptions with
status=activeandstatus=past_dueusing the List Subscriptions endpoint. Paginate through all results. - For each subscription, iterate over
items.data. Each item has apriceobject withunit_amount,recurring.interval, andrecurring.interval_count. - Normalize each item to a monthly amount using the formulas above. Multiply
unit_amountbyquantityfirst. - Sum all normalized amounts to get total MRR.
The main gotcha is pagination — if you have more than 100 subscriptions, you'll need to paginate through all of them. The has_more field and starting_after parameter handle this.
Automating MRR tracking
Building a one-time MRR calculation script is manageable. Keeping it running reliably — refreshing data, handling API rate limits, tracking historical changes, breaking out movement categories — is where the ongoing work lives.
Tools like illumi connect to your Stripe account and calculate MRR automatically using the methodology described in this post (including the past_due inclusion and interval normalization). You also get MRR movement tracking, churn rate, and the ability to audit how every number is calculated by clicking on any metric. If you'd rather spend time on your product than building analytics infrastructure, it's worth a look.
Track your SaaS metrics with illumi
Connect your Stripe account and get MRR, churn, LTV, and cohort analytics in 30 seconds.
Start Free Trial