6 min read

What Is MRR in Stripe

Monthly Recurring Revenue (MRR) is the predictable revenue your business generates from active subscriptions each month. In Stripe, MRR isn't a native metric—you have to calculate it from your subscription data. Understanding your MRR is critical for forecasting, runway, and spotting growth or contraction early.

What MRR Actually Means in Stripe

MRR measures the monthly value of all active subscriptions. But Stripe subscriptions can have different billing intervals, so you need to normalize everything to a monthly value.

Understand the distinction: MRR vs. Total Billing

MRR is the recurring portion of your revenue, not one-time charges or usage-based overages. A customer on a $100/month subscription contributes $100 to MRR, regardless of add-ons or seat changes mid-cycle. Stripe tracks this through the subscription object in your Billing dashboard.

javascript
const stripe = require('stripe')('sk_live_...');

const subscription = await stripe.subscriptions.retrieve('sub_ABC123');

console.log({
  id: subscription.id,
  customer: subscription.customer,
  status: subscription.status,
  items: subscription.items.data.map(item => ({
    price: item.price.id,
    amount: item.price.unit_amount,
    interval: item.price.recurring.interval,
    interval_count: item.price.recurring.interval_count
  }))
});
Stripe subscription object structure—this is what you calculate MRR from

Convert non-monthly intervals to monthly equivalents

If a customer pays $1200 yearly, that's $100/month for MRR purposes. Stripe doesn't do this conversion for you—you do. Divide annual amounts by 12, weekly by 4.33 (weeks per month).

javascript
function getMrrFromPrice(unitAmount, interval, intervalCount) {
  const monthlyAmount = unitAmount / 100;
  
  switch (interval) {
    case 'month':
      return monthlyAmount * intervalCount;
    case 'year':
      return monthlyAmount / 12;
    case 'week':
      return monthlyAmount * 4.33;
    case 'day':
      return monthlyAmount * 30.44;
    default:
      return 0;
  }
}

const mrrFromYearly = getMrrFromPrice(120000, 'year', 1);
console.log(mrrFromYearly); // 100
Convert any billing interval to monthly recurring value
Watch out: Trial periods don't count toward MRR until the trial ends and subscription status is active. Stripe shows this in the current_period_end field.

Calculate Total MRR from Your Active Subscriptions

To get your full MRR, sum the monthly values of all active subscriptions. Stripe's API makes this straightforward with status filtering.

List all active subscriptions with pagination

Use the List Subscriptions API endpoint with status: 'active' filter. This returns paginated results (100 max per page), so handle pagination if you have thousands of customers.

javascript
const stripe = require('stripe')('sk_live_...');

async function getAllActiveSubscriptions() {
  let allSubscriptions = [];
  let hasMore = true;
  let startingAfter = null;
  
  while (hasMore) {
    const subs = await stripe.subscriptions.list({
      status: 'active',
      limit: 100,
      starting_after: startingAfter
    });
    
    allSubscriptions = allSubscriptions.concat(subs.data);
    hasMore = subs.has_more;
    if (hasMore) {
      startingAfter = subs.data[subs.data.length - 1].id;
    }
  }
  
  return allSubscriptions;
}
Fetch all active subscriptions with pagination

Calculate total MRR by summing all active items

Loop through each subscription and each line item (price). Convert to monthly equivalent and sum. Subscriptions can have multiple items, so iterate all of them.

javascript
function calculateTotalMrr(subscriptions) {
  let totalMrr = 0;
  
  for (const sub of subscriptions) {
    for (const item of sub.items.data) {
      const unitAmount = item.price.unit_amount || 0;
      const interval = item.price.recurring?.interval || 'month';
      const intervalCount = item.price.recurring?.interval_count || 1;
      
      let monthlyValue = unitAmount / 100;
      if (interval === 'year') {
        monthlyValue /= 12;
      } else if (interval === 'week') {
        monthlyValue *= 4.33;
      }
      
      totalMrr += monthlyValue;
    }
  }
  
  return Math.round(totalMrr * 100) / 100;
}

const subs = await getAllActiveSubscriptions();
const mrr = calculateTotalMrr(subs);
console.log(`Current MRR: $${mrr.toFixed(2)}`);
Sum MRR across all active subscriptions
Tip: Run this daily or after each subscription event. Set up Stripe webhooks (customer.subscription.created, updated, deleted) so you recalculate only when something changes instead of fetching all subscriptions.

Track MRR Changes Through Webhooks

Knowing your current MRR matters less than knowing how it's changing—churn, expansion, new customers. Webhooks let you capture these events in real-time.

Set up webhooks in Stripe Dashboard

Go to Developers > Webhooks and add an endpoint. Choose these events: customer.subscription.created, customer.subscription.updated, customer.subscription.deleted. Stripe sends POST requests to your endpoint URL whenever these events occur.

Handle webhook events to calculate MRR impact

Validate the webhook signature, parse the event, and log the MRR change. created increases MRR, updated might increase or decrease it (upgrade/downgrade), deleted decreases MRR. Use event data to avoid re-querying all subscriptions.

javascript
const express = require('express');
const app = express();
const stripe = require('stripe')('sk_live_...');

app.post('/webhooks/stripe', express.raw({type: 'application/json'}), async (req, res) => {
  const sig = req.headers['stripe-signature'];
  const endpointSecret = 'whsec_...';
  
  try {
    const event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
    
    if (event.type === 'customer.subscription.created') {
      const sub = event.data.object;
      const mrrChange = calculateTotalMrr([sub]);
      console.log(`New subscription +$${mrrChange} MRR`);
    }
    
    if (event.type === 'customer.subscription.updated') {
      const sub = event.data.object;
      console.log(`Updated subscription: ${sub.id}`);
    }
    
    if (event.type === 'customer.subscription.deleted') {
      const sub = event.data.object;
      const mrrLoss = calculateTotalMrr([sub]);
      console.log(`Cancelled subscription -$${mrrLoss} MRR`);
    }
    
    res.json({received: true});
  } catch (err) {
    res.status(400).send(`Webhook Error: ${err.message}`);
  }
});
Webhook handler to track MRR changes in real-time
Tip: Save daily MRR snapshots to your own database. Stripe's API doesn't store historical MRR—you have to build a time series yourself to chart trends.

Common Pitfalls

  • Forgetting to normalize different billing intervals—annual plans will inflate or distort your MRR if you don't convert to monthly.
  • Including trial subscriptions or cancelled subscriptions—only count status active.
  • Counting one-time charges or metered usage as MRR—they're revenue, but not recurring.
  • Not accounting for paused subscriptions—pause_at is Stripe's way of keeping a subscription alive but inactive; don't count paused revenue in MRR.

Wrapping Up

MRR is the foundation of subscription metrics. Stripe gives you the data through subscriptions.list() and webhooks, but you do the calculation. Calculate weekly, segment by plan, and track trends over time. If you want to track MRR automatically across Stripe and other tools with dashboards and cohort analysis, Product Analyst can help.

Track these metrics automatically

Product Analyst connects to your stack and surfaces the insights that matter.

Try Product Analyst — Free