ARPU (Average Revenue Per User) is one of the most critical SaaS metrics — it tells you how much revenue each customer generates. In Stripe, your billing data is already there; you just need to query it right. We'll walk through pulling customer and revenue data, then calculating ARPU so you can track how your monetization is trending.
Pull Customers and Revenue Data
Start by fetching your customers and their revenue for a specific time period. You'll use Stripe's API to list customers, then their associated invoices.
Fetch all customers from your Stripe account
Use the Customers API endpoint to retrieve your customer list. You can paginate through results using the limit parameter (max 100 per request) and starting_after for pagination.
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const customers = await stripe.customers.list({
limit: 100
});
console.log(`Found ${customers.data.length} customers`);
// Use customers.data[0].id for the next stepSum revenue for each customer in your time period
For each customer, fetch their invoices using the Invoices API filtered by creation date. Sum the amount_paid field for invoices with status: 'paid' only. This gives you the revenue per customer.
const startDate = Math.floor(new Date('2024-01-01').getTime() / 1000);
const endDate = Math.floor(new Date('2024-03-31').getTime() / 1000);
let totalRevenue = 0;
const customerRevenue = {};
for (const customer of customers.data) {
const invoices = await stripe.invoices.list({
customer: customer.id,
created: {
gte: startDate,
lte: endDate
},
status: 'paid'
});
const customerTotal = invoices.data.reduce(
(sum, inv) => sum + inv.amount_paid,
0
) / 100; // Convert cents to dollars
customerRevenue[customer.id] = customerTotal;
totalRevenue += customerTotal;
}
console.log(`Total revenue: $${totalRevenue}`);
console.log('Revenue by customer:', customerRevenue);status: 'paid' is critical — unpaid or draft invoices skew your numbers.Calculate ARPU and Understand the Metric
Divide total revenue by customer count
ARPU is simply total revenue divided by the number of customers. This is your baseline. Most teams track ARPU monthly or quarterly to spot growth trends.
const activeCustomerCount = Object.keys(customerRevenue).length;
const arpu = totalRevenue / activeCustomerCount;
console.log(`ARPU for Q1 2024: $${arpu.toFixed(2)}`);
console.log(`Breakdown: ${activeCustomerCount} customers, $${totalRevenue} revenue`);
// Store this in your analytics tool or database
const metric = {
period: 'Q1 2024',
arpu: parseFloat(arpu.toFixed(2)),
active_customers: activeCustomerCount,
total_revenue: totalRevenue,
calculated_at: new Date().toISOString()
};
console.log(JSON.stringify(metric));Account for refunds and paying-only customers
Decide upfront: is ARPU across all customers or only paying ones? For net revenue, subtract credit notes and refunds. Use stripe.creditNotes.list() to fetch refunded amounts and deduct them from total revenue.
// Option A: ARPU for paying customers only (exclude $0 revenue)
const payingCustomers = Object.values(customerRevenue).filter(rev => rev > 0);
const arpuPayingOnly = totalRevenue / payingCustomers.length;
console.log(`ARPU (paying customers): $${arpuPayingOnly.toFixed(2)}`);
// Option B: Subtract refunds for net revenue
let netRevenue = totalRevenue;
for (const customer of customers.data) {
const creditNotes = await stripe.creditNotes.list({
customer: customer.id,
created: { gte: startDate, lte: endDate }
});
const refunded = creditNotes.data.reduce(
(sum, note) => sum + note.amount,
0
) / 100;
netRevenue -= refunded;
}
const arpuNet = netRevenue / activeCustomerCount;
console.log(`ARPU (net of refunds): $${arpuNet.toFixed(2)}`);
// Choose the definition that matches your business modelAutomate ARPU Calculation
Run this on a schedule with a serverless function
Use a cloud function (AWS Lambda, Vercel Cron, or Google Cloud Functions) to calculate ARPU daily or weekly. Store results in a database so you can chart ARPU over time and spot trends.
// Example: Vercel Cron Job at /api/cron/calculate-arpu.js
export default async function handler(req, res) {
// Verify the cron secret to prevent unauthorized calls
if (req.headers['authorization'] !== `Bearer ${process.env.CRON_SECRET}`) {
return res.status(401).json({ error: 'Unauthorized' });
}
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const now = new Date();
const startDate = Math.floor(new Date(now.getFullYear(), now.getMonth(), 1).getTime() / 1000);
const endDate = Math.floor(now.getTime() / 1000);
// Insert ARPU calculation logic from above here
// Then POST results to your metrics database
const result = { arpu: 125.50, period: `${now.toLocaleString('en-US', { month: 'short' })} ${now.getFullYear()}` };
await fetch('https://your-api.com/metrics/arpu', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${process.env.API_KEY}` },
body: JSON.stringify(result)
});
res.status(200).json({ success: true, arpu: result.arpu });
}Common Pitfalls
- Stripe amounts are in cents — forgetting to divide by 100 makes your ARPU 100x too high
- Including unpaid invoices — always filter by
status: 'paid'or you're counting revenue that never landed - Not deciding whether ARPU includes non-paying customers — this changes your metric significantly and confuses trend analysis
- Ignoring refunds and credit notes — net ARPU should subtract refunded amounts, not report gross charges
Wrapping Up
Now you can pull ARPU directly from your Stripe data and track it over time. The key is understanding your customer base's revenue distribution — some customers pay 10x more than others, and ARPU smooths that into one actionable number. If you want to track this automatically across tools, Product Analyst can help.