6 min read

How to Calculate ARR in Stripe

ARR (Annual Recurring Revenue) is your revenue normalized to a 12-month basis—critical for SaaS metrics. Stripe doesn't calculate this automatically, so you need to query subscription data and normalize for billing frequency.

Query active subscriptions via the Stripe API

First, pull all active subscriptions. Stripe's API returns paginated results, so handle pagination if you have thousands of subscriptions.

Fetch active subscriptions from Stripe

Use the Subscriptions endpoint (or the Node SDK) to list all subscriptions with status: 'active'. This filters out canceled or past-due subscriptions.

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

const subscriptions = await stripe.subscriptions.list({
  status: 'active',
  limit: 100,
});

console.log(subscriptions.data);
List all active subscriptions; use pagination to handle 100+ results

Handle pagination for large subscription lists

If you have more than 100 subscriptions, use the starting_after parameter to paginate through results.

javascript
let allSubscriptions = [];
let hasMore = true;
let startingAfter = undefined;

while (hasMore) {
  const batch = await stripe.subscriptions.list({
    status: 'active',
    limit: 100,
    starting_after: startingAfter,
  });
  
  allSubscriptions = allSubscriptions.concat(batch.data);
  hasMore = batch.has_more;
  
  if (batch.data.length > 0) {
    startingAfter = batch.data[batch.data.length - 1].id;
  }
}
Loop through paginated results to collect all subscriptions
Watch out: By default, Stripe's API returns subscriptions in reverse-chronological order. Add created[gte]: timestamp if you only want subscriptions created after a certain date.

Calculate ARR from billing amounts and cycles

ARR depends on the billing cycle. Stripe subscriptions can be monthly, annual, weekly, or daily. Normalize everything to a 12-month basis.

Extract the subscription amount and billing interval

Each subscription has an items array with pricing details. The price object contains recurring data: interval (month, year, week, day) and interval_count (e.g., 2 for every 2 months).

javascript
const sub = subscriptions.data[0];
const priceItem = sub.items.data[0];
const { amount, currency } = priceItem.price;
const { interval, interval_count } = priceItem.price.recurring;

console.log(`Amount: $${(amount / 100).toFixed(2)} ${currency}, Billing: every ${interval_count} ${interval}(s)`);

Calculate ARR using the billing interval

Convert the subscription amount to a 12-month basis by multiplying by the number of billing periods per year. The formula varies by interval type—the function below handles all cases.

javascript
function calculateArrForSubscription(subscription) {
  const priceItem = subscription.items.data[0];
  const amount = priceItem.price.amount;
  const { interval, interval_count } = priceItem.price.recurring;
  
  const intervalsPerYear = {
    'day': 365,
    'week': 52,
    'month': 12,
    'year': 1,
  };
  
  const arr = amount * (intervalsPerYear[interval] / interval_count);
  return arr / 100; // Convert cents to dollars
}

const arr = calculateArrForSubscription(sub);
console.log(`ARR: $${arr.toFixed(2)}`);
Tip: Handle multi-item subscriptions (bundles) by summing ARR across all items in the items array. Account for discounts with discount.coupon.percent_off if you need net ARR.

Sum total ARR and handle edge cases

Once you have ARR per subscription, aggregate to get total company ARR. Filter out trials and paused subscriptions.

Calculate total ARR across all subscriptions

Loop through all subscriptions, sum their ARR values, and convert from cents to dollars.

javascript
let totalArr = 0;

allSubscriptions.forEach(sub => {
  const arr = calculateArrForSubscription(sub);
  totalArr += arr;
});

console.log(`Total ARR: $${totalArr.toFixed(2)}`);

Filter out trial subscriptions if needed

Stripe subscriptions with a trial have a trial_end date in Unix timestamp. Exclude active trials by checking if trial_end > now.

javascript
let arr = 0;
const now = Math.floor(Date.now() / 1000);

allSubscriptions
  .filter(sub => !sub.trial_end || sub.trial_end < now) // Exclude active trials
  .forEach(sub => {
    arr += calculateArrForSubscription(sub);
  });

console.log(`ARR (excl. trials): $${arr.toFixed(2)}`);
Watch out: If a subscription has a balance from disputed charges, Stripe pauses it (status: 'past_due'). Check separately if you want to track revenue at risk.

Common Pitfalls

  • Forgetting to multiply by 12—if a subscription is $100/mo, ARR is $1,200, not $100
  • Not normalizing custom billing intervals (e.g., bi-weekly)—calculate based on frequency per year, not just interval type
  • Including paused or past_due subscriptions—these shouldn't count as active recurring revenue until resolved
  • Ignoring discounts and prorations—use invoice data if you need net ARR after discounts or one-time adjustments

Wrapping Up

ARR in Stripe requires summing subscription amounts and normalizing billing cycles. The query is straightforward with the Stripe API, but the calculation gets tricky with custom intervals and discounts. If you want to track this automatically across tools, Product Analyst can help.

Track these metrics automatically

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

Try Product Analyst — Free