MRR Break-Even Analysis

mrr
forecasting
growth
pricing
Author

Julian Winternheimer

Published

November 25, 2025

We’re migrating customers to a new pricing system where the cost per channel decreases as the number of channels increases. This is a strategic move to make our pricing more flexible and aligned with customer value, but it comes with a significant one-time cost. I estimate that we’ll take a one-time hit of around $65,000 in MRR.

In this the analysis I’ll try to estimate the amount of time it will take us to recover $65K in MRR to get back to our current leve.

This analysis uses our historical daily MRR data to forecast future growth and estimate the break-even timeline. I’ll also model a couple of scenarios where we increase new customer acquisition by 5% or 10% to see how much faster we could recover.

Key Takeaways

Based on current MRR values and channel distribution, I estimate that migrating all users to tiered pricing would result in an immediate loss of around $65,000 in MRR.

Based on our current growth trajectory, these are the estimated recovery timelines:

  1. No changes to customer acquisition: With no changes to customer acquisition, we’d recover the $65K MRR loss in around 70 days (early February 2026).

  2. If we boosted acquisition by 5% and nothing else changed: Increasing new customer acquisition by 5% would mean we’d recover the lost MRR in around 60 days.

  3. If we boosted acquisition by 10% and nothing else changed: Increasing new customer acquisition by 10% would mean we’d recover the lost MRR in around 52 days.

  4. If ASP decreased by 5%: If the new pricing resulted in a 5% decrease in average sales price for new customers, we’d recover the lost MRR in around 84 days, adding about 14 days to our baseline recovery timeline.

  5. If we staggered the migration over 3 months: Instead of taking the full $65K hit immediately, we could lose $21.7K per month on January 1, February 1, and March 1. After the final loss on March 1, it would take 70 days to recover to where we would have been without the migration (early May 2026). While this extends the total timeline to 166 days from today, we’d maintain higher MRR throughout the migration period.

  6. Realistic ASP impact from pricing changes: Based on our customer distribution, around 3.8% of new customers have 10+ channels and would receive a 12.5% discount under the new pricing. This results in a 0.475% overall ASP reduction, slowing our recovery by only 1 day compared to baseline (71 days total).

Loading Data

The data used comes from ChartMogul and contains the past 365 days of MRR data.

Code
library(dplyr)
library(ggplot2)
library(prophet)
library(lubridate)
library(scales)
library(RColorBrewer)

# Read the data
mrr_data <- read.csv("daily_mrr.csv") %>%
  mutate(date = as.Date(date))

# Current MRR (most recent value)
current_mrr <- mrr_data %>%
  filter(date == max(date)) %>%
  pull(mrr)

current_date <- max(mrr_data$date)

cat("Current MRR:", dollar(current_mrr), "\n")
Current MRR: $1,934,793 
Code
cat("Current Date:", as.character(current_date), "\n")
Current Date: 2025-11-25 

Baseline MRR Forecast

First we’ll forecast MRR for the next year using the prophet package. We know there were significant change-points on July 31 and August 26, 2025, when we proactively canceled plans of inactive Legacy customers, so we’ll include those in the model.

Code
# prepare data for Prophet
prophet_data <- mrr_data %>%
  select(ds = date, y = mrr)

# create Prophet model with weekly seasonality
m <- prophet(
  weekly.seasonality = TRUE,
  daily.seasonality = FALSE,
  changepoint.prior.scale = 0.05
)



# fit the model
m <- prophet(
  prophet_data,
  weekly.seasonality = TRUE,
  daily.seasonality = FALSE,
  changepoints = c("2025-07-31", "2025-08-26"),
  changepoint.prior.scale = 0.05
)

# make future dataframe for 365 days
future <- make_future_dataframe(m, periods = 365)

# generate forecast
forecast <- predict(m, future)

# extract forecast from today forward
future_forecast <- forecast %>%
  filter(ds > current_date) %>%
  select(ds, yhat, yhat_lower, yhat_upper)

head(future_forecast)
          ds    yhat yhat_lower yhat_upper
1 2025-11-26 1938642    1930156    1946299
2 2025-11-27 1939765    1931447    1948319
3 2025-11-28 1940674    1932821    1948547
4 2025-11-29 1940564    1933002    1948681
5 2025-11-30 1940575    1932517    1948938
6 2025-12-01 1942072    1933747    1949624

The resulting future_forecast object contains our projected MRR for the next year.

Average Daily MRR Growth

To estimate the recovery timeline we’ll want to extract the average daily growth rate from the forecast.

Code
# calculate daily growth rate from forecast
daily_growth <- future_forecast %>%
  mutate(daily_change = yhat - lag(yhat)) %>%
  filter(!is.na(daily_change))

# calculate average daily MRR growth
avg_daily_growth <- mean(daily_growth$daily_change)

# print result
cat("Average daily MRR growth:", dollar(avg_daily_growth), "\n")
Average daily MRR growth: $934.36 

The forecast model predicts we’ll grow MRR by about $934 per day on average over the next year. This accounts for weekly seasonality (i.e. slower growth on weekends).

Scenario 1: One-Time 65K MRR Loss

If we lose $65,000 in MRR today, the number of days it will take for us to recover will roughly be 65,000 divided by our average daily growth ($934/day). This simple calculation gives us an initial estimate of around 70 days to recover the initial MRR loss.

Code
# Calculate MRR after 65K loss
mrr_after_loss <- current_mrr - 65000

# Calculate days to recover
mrr_gap <- current_mrr - mrr_after_loss
days_to_recover <- ceiling(mrr_gap / avg_daily_growth)

cat("MRR after 65K loss:", dollar(mrr_after_loss), "\n")
MRR after 65K loss: $1,869,793 
Code
cat("Days to recover:", days_to_recover, "days\n")
Days to recover: 70 days
Code
cat("Recovery date:", as.character(current_date + days_to_recover), "\n")
Recovery date: 2026-02-03 
Code
# Create scenario dataframe
scenario_1 <- data.frame(
  ds = seq(current_date, current_date + days_to_recover, by = "day")
) %>%
  mutate(
    day_num = row_number() - 1,
    yhat = mrr_after_loss + (day_num * avg_daily_growth)
  )

If the migration happened today, this would mean that we’d break even by February 3, 2026. Let’s plot this scenario out.

Scenario 2: 65K Loss + 5% More New Customers

What if this pricing changed helped us increase new customer acquisition by 5%? Currently we acquire around 161.8 new customers per day at $19.57 in MRR per customer on average. A 5% uptick in new customer acquisition would add an additional $158 (161.8 daily customers * 0.05 * $19.57 ASP) in daily MRR growth, bringing our total growth rate to around $1,093 per day.

The simple calculation of 65,000 divided by 1,093 equates to around 60 days to recover the lost MRR.

Code
# calculate average new customers per day
avg_new_customers <- mean(mrr_data$new_biz_customer_count, na.rm = TRUE)

# calculate average MRR per new customer
avg_mrr_per_customer <- mean(
  mrr_data$new_biz_mrr / mrr_data$new_biz_customer_count,
  na.rm = TRUE
)

# 5% increase in new customers
additional_customers_5pct <- avg_new_customers * 0.05
additional_daily_mrr_5pct <- additional_customers_5pct * avg_mrr_per_customer

# new growth rate
boosted_growth_5pct <- avg_daily_growth + additional_daily_mrr_5pct

# days to recover with 5% boost
days_to_recover_5pct <- ceiling(mrr_gap / boosted_growth_5pct)

cat("Days to recover:", days_to_recover_5pct, "days\n")
Days to recover: 60 days
Code
cat("Days saved:", days_to_recover - days_to_recover_5pct, "days\n")
Days saved: 10 days

Let’s plot this new trajectory.

Scenario 3: 65K Loss + 10% More New Customers

What if this pricing change helped us increase new customer acquisition by 10%? Doubling that acquisition boost to 10% would add an additional $317 in daily MRR growth (161.8 daily customers * 0.10 * $19.57 ASP), pushing our total growth rate to around $1,251 per day.

65,000 divided by 1,251 equates to around 52 days to recover the lost MRR.

Code
# 10% increase in new customers
additional_customers_10pct <- avg_new_customers * 0.10
additional_daily_mrr_10pct <- additional_customers_10pct * avg_mrr_per_customer

# new growth rate
boosted_growth_10pct <- avg_daily_growth + additional_daily_mrr_10pct

# days to recover with 10% boost
days_to_recover_10pct <- ceiling(mrr_gap / boosted_growth_10pct)

cat("Days to recover:", days_to_recover_10pct, "days\n")
Days to recover: 52 days
Code
cat("Days saved:", days_to_recover - days_to_recover_10pct, "days\n")
Days saved: 18 days

Let’s plot this new trajectory.

Scenario 4: 65K Loss + 5% ASP Decrease

What if the new pricing structure resulted in a 5% decrease in average sales price for new customers going forward? This would slow down our MRR growth since each new customer would contribute less revenue. With ASP dropping from $19.57 to $18.59 ($19.57 * 0.95), our daily MRR growth would decrease by around $81 to about $853 per day.

65,000 divided by 853 equates to around 76 days to recover the lost MRR.

Code
# 5% decrease in ASP
reduced_asp <- avg_mrr_per_customer * 0.95

# Calculate reduction in daily MRR growth
asp_impact <- avg_new_customers * (avg_mrr_per_customer - reduced_asp)

# New growth rate with reduced ASP
reduced_growth_asp <- avg_daily_growth - asp_impact

# Days to recover with reduced ASP
days_to_recover_asp <- ceiling(mrr_gap / reduced_growth_asp)

cat("Original ASP:", dollar(avg_mrr_per_customer), "\n")
Original ASP: $19.57 
Code
cat("Reduced ASP:", dollar(reduced_asp), "\n")
Reduced ASP: $18.59 
Code
cat("Daily growth impact:", dollar(asp_impact), "\n")
Daily growth impact: $158.35 
Code
cat("New daily growth rate:", dollar(reduced_growth_asp), "\n")
New daily growth rate: $776.01 
Code
cat("Days to recover:", days_to_recover_asp, "days\n")
Days to recover: 84 days
Code
cat("Additional days vs baseline:", days_to_recover_asp - days_to_recover, "days\n")
Additional days vs baseline: 14 days

Here’s the plot for this scenario.

Scenario 5: Staggered Loss (21.7K over 3 Months)

What if instead of taking the full $65K MRR hit all at once, we staggered the migration over three months? In this scenario we’d lose $21.7K on January 1, another $21.7K on February 1, and the final $21.7K on March 1.

This approach means we’re always operating at a higher MRR level compared to taking the full loss immediately. The trade-off is that it takes longer before all customers are migrated. Let’s model how long it takes from the final loss (March 1) to recover back to where we would have been without any losses.

Code
# Staggered losses
loss_per_month <- 65000 / 3
loss_dates <- as.Date(c("2026-01-01", "2026-02-01", "2026-03-01"))

# Create a dataframe to track MRR over time with staggered losses
# Compare to immediate loss scenario
staggered_scenario <- data.frame(
  ds = seq(current_date + 1, current_date + 365, by = "day")
) %>%
  left_join(
    future_forecast %>% select(ds, baseline_yhat = yhat),
    by = "ds"
  ) %>%
  mutate(
    # Calculate cumulative loss based on date
    cumulative_loss = case_when(
      ds < loss_dates[1] ~ 0,
      ds >= loss_dates[1] & ds < loss_dates[2] ~ loss_per_month,
      ds >= loss_dates[2] & ds < loss_dates[3] ~ loss_per_month * 2,
      ds >= loss_dates[3] ~ loss_per_month * 3,
      TRUE ~ 0
    ),
    yhat_staggered = baseline_yhat - cumulative_loss,
    # Immediate loss scenario for comparison
    yhat_immediate = baseline_yhat - 65000
  )

# On March 1 (final loss date), what's the MRR gap?
march_1_data <- staggered_scenario %>%
  filter(ds == loss_dates[3])

march_1_baseline <- march_1_data$baseline_yhat  # What MRR would be without migration
march_1_actual <- march_1_data$yhat_staggered   # What MRR will be after final loss
march_1_gap <- march_1_baseline - march_1_actual

# How long to recover that gap at our daily growth rate?
days_from_final_loss_to_recovery <- ceiling(march_1_gap / avg_daily_growth)

# Find actual recovery date
recovery_row <- staggered_scenario %>%
  filter(ds >= loss_dates[3]) %>%
  filter(yhat_staggered >= march_1_baseline) %>%
  slice(1)

# Total days from today
days_to_final_loss <- as.numeric(difftime(loss_dates[3], current_date, units = "days"))
days_to_recover_staggered <- days_to_final_loss + days_from_final_loss_to_recovery

cat("Loss per month:", dollar(loss_per_month), "\n")
Loss per month: $21,666.67 
Code
cat("Loss dates:", paste(loss_dates, collapse = ", "), "\n")
Loss dates: 2026-01-01, 2026-02-01, 2026-03-01 
Code
cat("\nMRR on March 1 (final loss date):\n")

MRR on March 1 (final loss date):
Code
cat("  Baseline forecast (no migration):", dollar(march_1_baseline), "\n")
  Baseline forecast (no migration): $2,025,602 
Code
cat("  After final loss:", dollar(march_1_actual), "\n")
  After final loss: $1,960,602 
Code
cat("  Gap to close:", dollar(march_1_gap), "\n")
  Gap to close: $65,000 
Code
cat("\nRecovery timeline from March 1:\n")

Recovery timeline from March 1:
Code
cat("  Days to recover:", days_from_final_loss_to_recovery, "days\n")
  Days to recover: 70 days
Code
cat("  Recovery date:", as.character(recovery_row$ds), "\n")
  Recovery date: 2026-05-08 
Code
cat("\nTotal timeline from today:\n")

Total timeline from today:
Code
cat("  Days to final loss:", days_to_final_loss, "days\n")
  Days to final loss: 96 days
Code
cat("  Days from final loss to recovery:", days_from_final_loss_to_recovery, "days\n")
  Days from final loss to recovery: 70 days
Code
cat("  Total days:", days_to_recover_staggered, "days\n")
  Total days: 166 days

If we took this staggered approach, it would take us almost 6 months from today to fully recover the $65K of MRR that will be lost. From the day of the final loss, March 1, 2026, it would still take around 70 days to recover to what MRR would have been had there been no migration.

Let’s visualize how this staggered approach compares to the immediate loss scenario.

Scenario 6: Realistic ASP Impact from Pricing Changes

Let’s model a more realistic ASP scenario based on our customer distribution. Around 3.8% of new customers have more than 10 channels, and our pricing changes will give these customers a 12.5% MRR discount compared to what they would have previously paid.

This means the overall ASP impact is: 3.8% of customers × 12.5% discount = 0.475% overall ASP reduction.

Code
# Realistic ASP calculation
pct_customers_affected <- 0.038  # 3.8% of new customers have 10+ channels
discount_for_affected <- 0.125  # 12.5% discount for those customers
overall_asp_reduction <- pct_customers_affected * discount_for_affected

# New ASP
realistic_reduced_asp <- avg_mrr_per_customer * (1 - overall_asp_reduction)

# Calculate reduction in daily MRR growth
realistic_asp_impact <- avg_new_customers * (avg_mrr_per_customer - realistic_reduced_asp)

# New growth rate with realistic ASP reduction
realistic_reduced_growth <- avg_daily_growth - realistic_asp_impact

# Days to recover with realistic ASP reduction
days_to_recover_realistic_asp <- ceiling(mrr_gap / realistic_reduced_growth)

cat("Customers affected:", percent(pct_customers_affected), "\n")
Customers affected: 4% 
Code
cat("Discount for affected customers:", percent(discount_for_affected), "\n")
Discount for affected customers: 12% 
Code
cat("Overall ASP reduction:", percent(overall_asp_reduction), "\n")
Overall ASP reduction: 0% 
Code
cat("Original ASP:", dollar(avg_mrr_per_customer), "\n")
Original ASP: $19.57 
Code
cat("New ASP:", dollar(realistic_reduced_asp), "\n")
New ASP: $19.48 
Code
cat("Daily growth impact:", dollar(realistic_asp_impact), "\n")
Daily growth impact: $15.04 
Code
cat("New daily growth rate:", dollar(realistic_reduced_growth), "\n")
New daily growth rate: $919.32 
Code
cat("Days to recover:", days_to_recover_realistic_asp, "days\n")
Days to recover: 71 days
Code
cat("Additional days vs baseline:", days_to_recover_realistic_asp - days_to_recover, "days\n")
Additional days vs baseline: 1 days

Here’s what this scenario looks like.

Summary

The table below summarizes all six scenarios we’ve covered.

The customer acquisition requirements are calculated by multiplying the average number of customers acquired per day (161.8) by the number of days to break even in each scenario.

Code
# Calculate total customers for each scenario (needed for summary table)
total_customers_baseline <- avg_new_customers * days_to_recover
total_customers_5pct <- (avg_new_customers * 1.05) * days_to_recover_5pct
total_customers_10pct <- (avg_new_customers * 1.10) * days_to_recover_10pct
total_customers_asp <- avg_new_customers * days_to_recover_asp
total_customers_staggered <- avg_new_customers * days_to_recover_staggered
total_customers_realistic_asp <- avg_new_customers * days_to_recover_realistic_asp

summary_df <- data.frame(
  Scenario = c(
    "Baseline (65K loss)",
    "+5% New Customers",
    "+10% New Customers",
    "5% ASP Decrease",
    "Staggered Loss (3 months)",
    "Realistic ASP (0.475% decrease)"
  ),
  `Daily Growth` = dollar(c(
    avg_daily_growth,
    boosted_growth_5pct,
    boosted_growth_10pct,
    reduced_growth_asp,
    avg_daily_growth,
    realistic_reduced_growth
  )),
  `Days to Recover` = c(
    days_to_recover,
    days_to_recover_5pct,
    days_to_recover_10pct,
    days_to_recover_asp,
    days_to_recover_staggered,
    days_to_recover_realistic_asp
  ),
  `Recovery Date` = as.character(c(
    current_date + days_to_recover,
    current_date + days_to_recover_5pct,
    current_date + days_to_recover_10pct,
    current_date + days_to_recover_asp,
    recovery_row$ds,
    current_date + days_to_recover_realistic_asp
  )),
  `Days vs Baseline` = c(
    0,
    days_to_recover_5pct - days_to_recover,
    days_to_recover_10pct - days_to_recover,
    days_to_recover_asp - days_to_recover,
    days_to_recover_staggered - days_to_recover,
    days_to_recover_realistic_asp - days_to_recover
  ),
  `Daily New Customers` = round(c(
    avg_new_customers,
    avg_new_customers * 1.05,
    avg_new_customers * 1.10,
    avg_new_customers,
    avg_new_customers,
    avg_new_customers
  ), 1),
  `Total New Customers` = comma(round(c(
    total_customers_baseline,
    total_customers_5pct,
    total_customers_10pct,
    total_customers_asp,
    total_customers_staggered,
    total_customers_realistic_asp
  ), 0))
)

knitr::kable(summary_df, align = "lrrrrrr")
Scenario Daily.Growth Days.to.Recover Recovery.Date Days.vs.Baseline Daily.New.Customers Total.New.Customers
Baseline (65K loss) $934.36 70 2026-02-03 0 161.8 11,327
+5% New Customers $1,092.72 60 2026-01-24 -10 169.9 10,194
+10% New Customers $1,251.07 52 2026-01-16 -18 178.0 9,256
5% ASP Decrease $776.01 84 2026-02-17 14 161.8 13,592
Staggered Loss (3 months) $934.36 166 2026-05-08 96 161.8 26,861
Realistic ASP (0.475% decrease) $919.32 71 2026-02-04 1 161.8 11,489