Skip to content

Instantly share code, notes, and snippets.

@dpaluy
Created January 11, 2021 16:46
Show Gist options
  • Select an option

  • Save dpaluy/bb4a327fa02b197fe31fbc1e2d134dbd to your computer and use it in GitHub Desktop.

Select an option

Save dpaluy/bb4a327fa02b197fe31fbc1e2d134dbd to your computer and use it in GitHub Desktop.
Baremetrics alternative using Ruby
# retrieve subscription data
########################
Stripe.api_key = ENV.fetch('STRIPE_SECRET_KEY')
subscriptions =
Stripe::Subscription.list(status: 'all', limit: 100, expand: ['data.customer'])
# Retrieve all subscriptions, following pagination until complete.
.auto_paging_each
.to_a
# Filter out deleted customers.
.filter { |s| !s.customer.deleted? }
# Remove duplicate subscriptions per-customer. Keep the latest.
.sort_by { |s| [s.customer.id, -s.created] }
.uniq { |s| s.customer.id }
# calculate MRR
########################
paid_subscriptions = subscriptions.filter { |s| s.status == 'active' }
revenue_per_user = paid_subscriptions.map { |s| s.plan.amount.to_f * s.quantity / 100 }
monthly_recurring_revenue = revenue_per_user.sum(0.0)
# calculate ARR
########################
annual_run_rate = monthly_recurring_revenue * 12
# calculate ARPU
########################
average_revenue_per_user =
revenue_per_user.sum(0.0) / revenue_per_user.size
# calculate conversion rate
########################
new_paid_subscriptions = paid_subscriptions.filter { |s| s.created >= 1.month.ago.to_i }
new_subscriptions = subscriptions.filter { |s| s.created >= 1.month.ago.to_i }
conversion_rate = new_paid_subscriptions.size.to_f / new_subscriptions.size * 100
# calculate churn rate
########################
canceled_subscriptions = subscriptions.filter { |s| s.status == 'canceled' }
churned_subscriptions =
canceled_subscriptions
# Select only recent cancelations.
.filter { |s| s.canceled_at >= 1.month.ago.to_i || s.ended_at >= 1.month.ago.to_i }
# Filter out customers who never added a payment method, i.e. an unconverted trial.
.filter { |s| s.customer.default_source.present? }
paid_subscriptions_count_at_period_start =
(paid_subscriptions.size - new_paid_subscriptions.size) + churned_subscriptions.size
churn_rate =
churned_subscriptions.size.to_f / paid_subscriptions_count_at_period_start * 100
# calculate LTV
########################
converted_subscriptions =
(paid_subscriptions + canceled_subscriptions)
# Filter out canceled customers who never added a payment method.
.filter { |s| s.customer.default_source.present? }
subscription_durations =
converted_subscriptions
.map { |s| ((s.ended_at || Time.now) - s.created) / 1.month }
average_subscription_duration =
subscription_durations.sum(0.0) / subscription_durations.size
life_time_value =
average_revenue_per_user * average_subscription_duration
# calculate revenue growth rate
########################
next_mrr = monthly_recurring_revenue
prev_mrr = (next_mrr - new_revenue) + lost_revenue
revenue_growth_rate =
(next_mrr - prev_mrr) / prev_mrr * 100
# Time to Convert
########################
invoices =
Stripe::Invoice.list(subscription: subscription.id, limit: 100)
.auto_paging_each
.to_a
# Sort invoices in ASC order, to make sure we can select their
# first paid invoice, not the most recent paid invoice.
sorted_invoices = invoices.sort_by { |i| i.created }
# Find their first paid invoice with an amount > 0.
first_paid_invoice = sorted_invoices.find { |i| i.amount_paid > 0 }
# Calculate the subscription's time-to-convert
time_to_convert =
first_paid_invoice.status_transitions.paid_at - subscription.customer.created
@dpaluy
Copy link
Author

dpaluy commented Jan 11, 2021

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment