5 min read

How to Calculate CAC Payback in Stripe

Your marketing team spent $50k acquiring customers last month, but you don't know when you'll break even on that investment. CAC payback period—how many months until a customer's revenue covers their acquisition cost—is essential for forecasting unit economics. Stripe has all the data you need; you just need to extract it correctly.

Pull Subscription and Customer Data from Stripe

Extract your revenue data using Stripe's API. You'll need customer acquisition dates and subscription amounts to calculate anything meaningful.

Fetch customers by creation date

Use the Customers API endpoint with a created filter to get all customers acquired during a specific period. Stripe returns the created timestamp (Unix seconds) for each customer, which marks their acquisition date.

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

// Get all customers created in January 2025
const customers = await stripe.customers.list({
  limit: 100,
  created: {
    gte: Math.floor(new Date('2025-01-01') / 1000),
    lte: Math.floor(new Date('2025-01-31T23:59:59') / 1000)
  }
});

customers.data.forEach(customer => {
  const acquiredDate = new Date(customer.created * 1000);
  console.log(`${customer.id}: acquired ${acquiredDate.toISOString()}`);
});
Filter customers by acquisition month

Get subscription revenue per customer

For each customer, fetch their Subscriptions and sum the unit_amount from active subscriptions. This gives you the monthly recurring revenue (MRR) per customer. Filter out trials and inactive subscriptions.

javascript
const customerId = 'cus_abc123';

const subscriptions = await stripe.subscriptions.list({
  customer: customerId,
  status: 'all'
});

let monthlyRevenue = 0;
subscriptions.data.forEach(sub => {
  // Only count active subs, exclude trials
  if (sub.status === 'active' && sub.items.data[0]) {
    const item = sub.items.data[0];
    // Check if billing is monthly
    if (item.price.recurring && item.price.recurring.interval === 'month') {
      monthlyRevenue += item.price.unit_amount / 100; // Convert from cents
    }
  }
});

console.log(`${customerId} MRR: $${monthlyRevenue.toFixed(2)}`);

Aggregate MRR by acquisition cohort

Group customers by their acquisition month, calculate each customer's MRR, then average it across the cohort. This tells you the expected monthly revenue from a typical customer acquired in that period.

javascript
const cohorts = {};

// Process all customers
for (const customer of customers.data) {
  const acquiredDate = new Date(customer.created * 1000);
  const cohortKey = `${acquiredDate.getFullYear()}-${String(acquiredDate.getMonth() + 1).padStart(2, '0')}`;
  
  // Get MRR for this customer
  const subs = await stripe.subscriptions.list({ customer: customer.id });
  let mrr = 0;
  subs.data.forEach(sub => {
    if (sub.status === 'active' && sub.items.data[0]?.price.recurring?.interval === 'month') {
      mrr += sub.items.data[0].price.unit_amount / 100;
    }
  });
  
  // Add to cohort
  if (!cohorts[cohortKey]) cohorts[cohortKey] = { count: 0, totalMRR: 0 };
  cohorts[cohortKey].count += 1;
  cohorts[cohortKey].totalMRR += mrr;
}

// Calculate average MRR per cohort
Object.entries(cohorts).forEach(([month, data]) => {
  const avgMRR = data.totalMRR / data.count;
  console.log(`${month}: ${data.count} customers, avg MRR $${avgMRR.toFixed(2)}`);
});
Watch out: Stripe returns timestamps in Unix seconds, not milliseconds. When filtering with created, multiply your date by Math.floor(new Date() / 1000). Also, Stripe's test mode shows up in API results unless you filter with stripe.objects.list({expand: ['data.default_source']})—explicitly exclude test mode in production dashboards.

Calculate CAC Payback Period

Now you have the average MRR per customer. Divide your acquisition spend by that MRR to get payback in months.

Get your CAC from marketing spend

Pull your total marketing spend for the cohort (ad spend, sales salaries, tools—whatever your company defines as acquisition cost) and divide by the number of customers acquired that month. Stripe doesn't track this, but you'll have it from your accounting system or ad platform.

javascript
// Example: spent $40k acquiring customers in January 2025
const marketingSpendJan = 40000;
const customersAcquiredJan = 200; // from cohorts data above

const CAC = marketingSpendJan / customersAcquiredJan;
console.log(`CAC for Jan cohort: $${CAC}`); // $200

Divide CAC by average MRR

The payback period is CAC divided by average monthly revenue per customer. The result is how many months until that customer's subscription revenue matches their acquisition cost.

javascript
const CAC = 200;        // $200 acquisition cost
const avgMRR = 50;     // $50 average monthly revenue (from cohort calculation)

const paybackMonths = CAC / avgMRR;
console.log(`CAC payback period: ${paybackMonths.toFixed(1)} months`);

// Example result: 4 months
// If this customer stays 12+ months, you've 3x'd your acquisition spend
Tip: This calculation assumes MRR stays stable. If customers churn in month 3, you never recoup CAC. Refine this by looking at retention curves—discount future revenue based on your actual churn rate. Also, if you have one-time charges mixed with subscriptions, be clear about what you're measuring: are you calculating payback on subscription revenue only, or total revenue?

Track Cohort Payback Over Time

Run this calculation monthly for each cohort to watch trends. Is CAC rising while payback lengthens? That's a signal to adjust your acquisition strategy.

Build a payback cohort table

Create a monthly table where each row is a cohort and columns show CAC, average MRR, and payback months. This tells you if new customers are becoming more expensive and harder to recoup.

javascript
// Assuming cohorts object from step 3 above and spending data
const marketingSpend = {
  '2025-01': 40000,
  '2025-02': 50000,
  '2025-03': 48000
};

const paybackAnalysis = {};

Object.entries(cohorts).forEach(([month, data]) => {
  const spend = marketingSpend[month] || 0;
  const cac = spend / data.count;
  const avgMRR = data.totalMRR / data.count;
  const payback = cac / avgMRR;
  
  paybackAnalysis[month] = {
    customers: data.count,
    CAC: cac.toFixed(2),
    avgMRR: avgMRR.toFixed(2),
    paybackMonths: payback.toFixed(1)
  };
});

console.table(paybackAnalysis);
// Output shows trends across months

Common Pitfalls

  • Forgetting to exclude test mode customers—Stripe test environment mixes with live data in API results. Use metadata or filter explicitly by mode when querying.
  • Including trial revenue—trials usually mean $0 MRR. Filter for status: 'active' and confirm unit_amount > 0 before summing.
  • Using gross revenue instead of net—don't forget refunds and chargebacks reduce your take-home. Pull from your Reports API if tracking net is critical.
  • Measuring payback on only one month of data—CAC payback requires cohort analysis over time. A customer acquired in January might not churn until October. Calculate payback multiple months out.

Wrapping Up

You now have a way to measure whether your acquisition spend pays back in reasonable time. Run this monthly per cohort to watch your unit economics. If you want to track this automatically across all your tools—not just Stripe—Product Analyst can help.

Track these metrics automatically

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

Try Product Analyst — Free