5 min read

How to Calculate ARPU in Stripe

ARPU—Average Revenue Per User—is critical for SaaS. Your Stripe dashboard shows total revenue, but not per-customer. You need to query your customers and charges to see which segments are actually driving value. This is how you build that number.

Fetch Customers and Sum Their Revenue

Start by pulling your customer list and all succeeded charges, then group revenue by customer.

Paginate through all customers

Use stripe.customers.list() to fetch customers 100 at a time. The response includes a has_more flag—loop until it's false.

javascript
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

let allCustomers = [];
let startingAfter = undefined;
let hasMore = true;

while (hasMore) {
  const response = await stripe.customers.list({
    limit: 100,
    starting_after: startingAfter,
  });
  
  allCustomers = allCustomers.concat(response.data);
  hasMore = response.has_more;
  startingAfter = response.data[response.data.length - 1]?.id;
}

console.log(`Total customers: ${allCustomers.length}`);
Paginate using has_more and starting_after to retrieve all customers

Group charges by customer

Call stripe.charges.list() with status: 'succeeded' to get only completed payments. Loop through all pages and sum the amount for each customer.

javascript
const revenueByCustomer = {};
let chargesStartingAfter = undefined;
let chargesHasMore = true;

while (chargesHasMore) {
  const response = await stripe.charges.list({
    limit: 100,
    starting_after: chargesStartingAfter,
    status: 'succeeded',
  });
  
  response.data.forEach(charge => {
    if (charge.customer) {
      revenueByCustomer[charge.customer] = (revenueByCustomer[charge.customer] || 0) + charge.amount;
    }
  });
  
  chargesHasMore = response.has_more;
  chargesStartingAfter = response.data[response.data.length - 1]?.id;
}

console.log('Revenue by customer (in cents):', revenueByCustomer);
Amounts are in cents; divide by 100 to get dollars

Calculate ARPU

Sum all revenues and divide by the number of customers who generated revenue. Convert from cents to dollars.

javascript
const customerIds = Object.keys(revenueByCustomer);
const totalRevenue = Object.values(revenueByCustomer).reduce((sum, amt) => sum + amt, 0);
const arpu = totalRevenue / customerIds.length / 100;

console.log(`Active customers: ${customerIds.length}`);
console.log(`Total revenue: $${(totalRevenue / 100).toFixed(2)}`);
console.log(`ARPU: $${arpu.toFixed(2)}`);
ARPU = Total Revenue ÷ Number of Customers
Watch out: This counts all customers who ever made a payment. If you want ARPU for a specific period, filter by the created timestamp on charges.

Calculate Period ARPU (Monthly, Quarterly)

All-time ARPU is useful, but monthly or quarterly ARPU is more actionable. Use date filters to isolate a time period.

Filter charges by date range

Pass a created object with gte and lte to stripe.charges.list(). Use Unix timestamps in seconds (not milliseconds).

javascript
// Get charges for January 2024
const startOfJan = Math.floor(new Date('2024-01-01').getTime() / 1000);
const endOfJan = Math.floor(new Date('2024-02-01').getTime() / 1000);

const charges = await stripe.charges.list({
  limit: 100,
  status: 'succeeded',
  created: {
    gte: startOfJan,
    lte: endOfJan,
  },
});

console.log(`${charges.data.length} charges in January`);
Convert JavaScript milliseconds to Unix seconds by dividing by 1000

Sum revenue and count unique customers

Loop through charges in the period and track unique customer IDs. Divide total revenue by unique customer count.

javascript
const periodRevenue = {};
const uniqueCustomers = new Set();

let pageStartingAfter = undefined;
let pageHasMore = true;

while (pageHasMore) {
  const pageCharges = await stripe.charges.list({
    limit: 100,
    starting_after: pageStartingAfter,
    status: 'succeeded',
    created: { gte: startOfJan, lte: endOfJan },
  });
  
  pageCharges.data.forEach(charge => {
    if (charge.customer) {
      periodRevenue[charge.customer] = (periodRevenue[charge.customer] || 0) + charge.amount;
      uniqueCustomers.add(charge.customer);
    }
  });
  
  pageHasMore = pageCharges.has_more;
  pageStartingAfter = pageCharges.data[pageCharges.data.length - 1]?.id;
}

const totalPeriodRevenue = Object.values(periodRevenue).reduce((sum, amt) => sum + amt, 0);
const periodArpu = totalPeriodRevenue / uniqueCustomers.size / 100;

console.log(`January ARPU: $${periodArpu.toFixed(2)}`);
Count only unique customers in the period, not total charges
Tip: Save these monthly snapshots. ARPU trending over quarters tells you if product changes or pricing adjustments are working.

Segment ARPU by Subscription Plan

ARPU differs by plan tier. Store plan info in customer metadata and calculate ARPU separately for each.

Tag customers with their plan

When creating or updating a customer, add a metadata object with their plan name. Use stripe.customers.create() or stripe.customers.update().

javascript
// Create a new customer with plan metadata
await stripe.customers.create({
  email: '[email protected]',
  metadata: {
    plan: 'pro',
    team: 'acme',
  },
});

// Update existing customer
await stripe.customers.update('cus_abc123', {
  metadata: {
    plan: 'enterprise',
  },
});
Metadata helps you segment customers later without database joins

Calculate ARPU per plan

Fetch all customers, filter by metadata.plan, then sum charges for each plan segment. Compare ARPU across tiers.

javascript
const plans = ['free', 'starter', 'pro', 'enterprise'];
const arpuByPlan = {};

// Fetch all customers once
let allCustomersForSegment = [];
let startingAfter = undefined;
let hasMore = true;

while (hasMore) {
  const response = await stripe.customers.list({
    limit: 100,
    starting_after: startingAfter,
  });
  allCustomersForSegment = allCustomersForSegment.concat(response.data);
  hasMore = response.has_more;
  startingAfter = response.data[response.data.length - 1]?.id;
}

for (const plan of plans) {
  const customersOnPlan = allCustomersForSegment.filter(c => c.metadata?.plan === plan);
  const planRevenue = {};
  
  for (const customer of customersOnPlan) {
    const charges = await stripe.charges.list({ customer: customer.id, status: 'succeeded' });
    planRevenue[customer.id] = charges.data.reduce((sum, ch) => sum + ch.amount, 0);
  }
  
  const totalRevenue = Object.values(planRevenue).reduce((sum, amt) => sum + amt, 0);
  arpuByPlan[plan] = totalRevenue / customersOnPlan.length / 100;
}

console.log(arpuByPlan);
Compare ARPU across tiers to identify your highest-value segment
Watch out: Stripe doesn't let you filter customers by metadata in the API—you have to fetch all and filter in code. For large bases, consider storing plan info in your own database and joining against Stripe customer IDs.

Common Pitfalls

  • Forgetting to paginate—Stripe limits results to 100 per page. Miss pagination and you're calculating ARPU on incomplete data.
  • Using milliseconds instead of Unix seconds—Stripe's created filter expects seconds. Divide JavaScript timestamps by 1000.
  • Including free or zero-revenue customers—ARPU should be total revenue ÷ paying customers, not all customers.
  • Not filtering by status: 'succeeded'—Refunds and failed charges skew ARPU down. Only count completed payments.

Wrapping Up

You now know how to calculate ARPU by period and plan directly from Stripe. Track it monthly to catch revenue trends early. If you want to calculate this automatically across all your tools and build dashboards without API queries, Product Analyst can help.

Track these metrics automatically

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

Try Product Analyst — Free