The maths behind it all: growth marketing mathematics explained

TL;DR

Difficulty: Intermediate

Growth decisions rest on a handful of formulas, and each one answers one question.

  • LTV to CAC and payback: is a customer worth what you paid, and how long until the money comes back. The usual SaaS guideline is a ratio above 3 and payback under 12 months.
  • Cohorts and survival curves show what a blended average and a single churn rate hide.
  • Bayesian tests and bandits give the probability that B is better and earn while they learn, but neither makes peeking free.
  • Attribution, mix models and power laws: credit journeys, credit channels, and stop trusting the average customer.
  • Elasticity and retention decide whether a price rise pays and why each point of retention is worth more than the last.

This is the working toolkit behind growth decisions: ten pieces of maths, from lifetime value against acquisition cost to the retention maths that ties them together. Each comes with its formula, every symbol explained, a worked example in euro and a short piece of Python, so a newcomer can follow and a practitioner can run it.

Why growth needs maths at all

Psychology gets people interested. Data gets you funded. Every principle in this series, from scarcity to habit formation, ends up as a number someone has to measure and defend. This is the last chapter, and it is the toolkit I use every day to make decisions about acquisition, retention, pricing and experiments.

If you are new to this, every idea comes with a plain explanation and a worked example. If you know your statistics, you get the formulas, the edge cases and short Python. Every business and number in the examples is made up, so the arithmetic can be shown in full, and each formula links to its section of the Foundations page.

Lifetime value against acquisition cost tells you whether growth pays

Lifetime value (LTV) is the total gross profit a customer generates over the whole relationship. Customer acquisition cost (CAC) is what you spent to win them. A customer is worth acquiring if the first is comfortably more than the second.

LTV=ARPU×m×LLTV = ARPU \times m \times L

Here LTVLTV is the lifetime value in euro, ARPUARPU is the average revenue per user in one period (a month, say), mm is the gross margin as a share between 0 and 1, and LL is the average customer lifespan in the same periods as ARPUARPU. Foundations: lifetime value

With a steady monthly churn rate the lifespan is one divided by churn (1/0.05=201 / 0.05 = 20 months at 5%), which gives:

LTV=ARPU×mcLTV = \frac{ARPU \times m}{c}

Here ARPUARPU and mm are as before and cc is the churn rate per period as a share, so 1/c1/c is the expected lifespan. It assumes the same churn every month. Foundations: lifetime value

The ratio itself:

R=LTVCACR = \frac{LTV}{CAC}

Here RR is the ratio, LTVLTV the lifetime value and CACCAC the average acquisition cost per new customer, both in euro. Foundations: ratios and rates

The common guideline comes from David Skok's SaaS metrics work: a healthy SaaS business has an LTV to CAC ratio above 3, and the best reach 7 or 8.1 He calls them guidelines, not laws. Below 1 you lose money on every customer you win.

Worked example: a rota app in Cork

Rotaglen (rotaglen.example) is an invented Cork SaaS selling rota software to cafés for €99 a month. Gross margin is 80%, monthly churn is 3%, and winning a customer costs €400.

  1. Lifespan: 1/0.03=33.31 / 0.03 = 33.3 months.
  2. Monthly gross profit per customer: 99×0.80=79.2099 \times 0.80 = 79.20 euro.
  3. Lifetime value: 79.20/0.03=2,64079.20 / 0.03 = 2{,}640 euro.
  4. Ratio: 2,640/400=6.62{,}640 / 400 = 6.6.

LTV to CAC ratio by monthly churnFor the invented Rotaglen example, the LTV to CAC ratio falls from 19.8 at 1% monthly churn to 2.0 at 10% churn.Rotaglen: LTV to CAC ratio by monthly churn06.312.518.82519.81%9.92%6.63%45%2.58%210%LTV to CAC ratioMonthly churn rate

The horizontal axis is monthly churn, the vertical axis the ratio for Rotaglen. Going from 3% to 5% churn takes the ratio from 6.6 to 4.0, and from 8% it is below the guideline of 3. One or two points of churn matter more than most acquisition tweaks.

def ltv(arpu, margin, churn):
    if churn <= 0:
        raise ValueError("churn must be positive")
    return arpu * margin / churn

cac = 400
for churn in [0.01, 0.02, 0.03, 0.05, 0.08, 0.10]:
    value = ltv(99, 0.80, churn)
    print(f"churn {churn:.0%}: LTV €{value:,.0f}, ratio {value / cac:.1f}")

Payback tells you whether you can afford the growth

Payback says how long you wait for the acquisition money to come back. That is a cash question: a two year payback means funding two years of acquisition before it recycles.

P=CACARPU×mP = \frac{CAC}{ARPU \times m}

Here PP is the payback period in months, CACCAC the acquisition cost, and ARPU×mARPU \times m the gross profit one customer brings in each month. Foundations: ratios and rates

For a business with €500 CAC, €100 a month ARPU and 80% gross margin:

P=500100×0.80=50080=6.25P = \frac{500}{100 \times 0.80} = \frac{500}{80} = 6.25

So P=6.25P = 6.25 months. Skok's second guideline is to recover CAC in under 12 months, and he notes that many of the best SaaS businesses manage five to seven.1

Worked example: payback when some customers leave first

Take an invented business with €500 CAC, €80 a month ARPU, 75% margin and 4% monthly churn, and count the first month as always paid.

  1. Monthly gross profit: 80×0.75=6080 \times 0.75 = 60 euro.
  2. Simple payback: 500/60=8.3500 / 60 = 8.3 months, so nine payments.
  3. Share of customers still paying in month nine: 0.968=0.720.96^{8} = 0.72. More than a quarter leave before their own acquisition cost is recovered.
  4. Across the whole group, the average gross profit per acquired customer after nn months is 60×(1+0.96+⋯+0.96n−1)60 \times (1 + 0.96 + \dots + 0.96^{n-1}). It passes €500 in month 10 (€502.75), not month nine.

Cohorts show what averages hide

A cohort is a group of customers who share a starting point, usually the month they first bought. Following each group over time shows what one blended average hides.

Worked example: two cohorts behind one average

Plassey Tea (plasseytea.example) is an invented Limerick tea subscription. Its 1,000 customers spend €50 a month on average. That looks fine. Split by cohort, 500 customers who joined in January spend €80 a month and 500 who joined in June spend €20:

500×80+500×201,000=50,0001,000=50\frac{500 \times 80 + 500 \times 20}{1{,}000} = \frac{50{,}000}{1{,}000} = 50

The blended 5050 euro hides a problem worth chasing. Retention works the same way. Read a cohort table down a column to compare cohorts at the same age, and along a row to see one cohort decay.

CohortCustomersMonth 1Month 3Month 6
January20060%45%38%
April22052%35%27%

April's customers fall away faster at every age, which a blended average would show only as a gentle decline. The same grouping gives revenue, lifetime value and CAC per cohort, a single groupby in pandas.

Survival analysis models churn the way it happens

A single churn rate treats a customer of one week like one of three years. Survival analysis, borrowed from medical statistics, models how long customers last and treats those who have not left yet honestly.2 The full treatment is in survival analysis, churn and customer lifetime value.

The survival function is the probability that a customer is still with you after time tt:

S(t)=P(T>t)S(t) = P(T > t)

Here TT is how long a customer lasts (a random variable), tt is a point in time such as 12 months, and P(T>t)P(T > t) is the probability that the lifetime is longer than tt. Foundations: probability

The hazard function is the rate of leaving at time tt among the customers who made it that far:

h(t)=lim⁡Δt→0P(t≤T<t+Δt∣T≥t)Δth(t) = \lim_{\Delta t \to 0} \frac{P(t \le T < t + \Delta t \mid T \ge t)}{\Delta t}

Here h(t)h(t) is the hazard at time tt, Δt\Delta t a small slice of time after tt, P(t≤T<t+Δt∣T≥t)P(t \le T < t + \Delta t \mid T \ge t) is the probability of leaving inside that slice given the customer was still there at tt, and the limit shrinks the slice towards zero. In plain words, the churn risk right now for a customer of this age. Foundations: probability

The Kaplan Meier estimator draws the survival curve from data without assuming any shape:3

S^(t)=∏ti≤t(1−dini)\hat{S}(t) = \prod_{t_i \le t} \left(1 - \frac{d_i}{n_i}\right)

Here S^(t)\hat{S}(t) is the estimated survival at time tt, tit_i are the times at which at least one customer left, did_i is the number who left at tit_i, nin_i is the number still at risk just before tit_i, and ∏\prod multiplies the factors for every tit_i up to tt. Customers still active (censored) count as at risk until their record ends, then drop out without counting as churn. Foundations: probability

Worked example: ten customers by hand

Ten invented Rotaglen customers. Five left, at months 1, 1, 2, 4 and 6. Five are still active, watched for 3, 5, 7, 8 and 8 months.

  1. Month 1: 10 at risk, 2 leave. S^=1−2/10=0.80\hat{S} = 1 - 2/10 = 0.80.
  2. Month 2: 8 at risk, 1 leaves. S^=0.80×7/8=0.70\hat{S} = 0.80 \times 7/8 = 0.70.
  3. Month 3: one record ends, nobody leaves, S^\hat{S} stays 0.70.
  4. Month 4: 6 at risk, 1 leaves. S^=0.70×5/6=0.583\hat{S} = 0.70 \times 5/6 = 0.583.
  5. Month 6: one more record ended at month 5, so 4 at risk, 1 leaves. S^=0.583×3/4=0.4375\hat{S} = 0.583 \times 3/4 = 0.4375.

So about 44% survive six months. A naive count (only three of ten records run past six months) would say 30%. The censored customers carry real information, and Kaplan Meier uses it.

def kaplan_meier(durations, churned):
    rows = sorted(zip(durations, churned))
    at_risk, s, curve = len(rows), 1.0, []
    for t in sorted({d for d, c in rows if c}):
        left = sum(1 for d, c in rows if d == t and c)
        at_risk = sum(1 for d, _ in rows if d >= t)
        s *= 1 - left / at_risk
        curve.append((t, at_risk, left, round(s, 4)))
    return curve

print(kaplan_meier([1, 1, 2, 3, 4, 5, 6, 7, 8, 8],
                   [1, 1, 1, 0, 1, 0, 1, 0, 0, 0]))

The log rank test checks whether two cohorts' curves differ by more than chance. The lifelines library implements both.3

Bayesian A/B tests answer the question you actually asked

A classical test, explained in the complete guide to digital marketing testing methods, asks how surprising the data would be if A and B were the same. A Bayesian test asks what you want to know: how likely is it that B is better? It rests on Bayes' theorem:

P(θ∣D)=P(D∣θ) P(θ)P(D)P(\theta \mid D) = \frac{P(D \mid \theta)\, P(\theta)}{P(D)}

Here θ\theta is the unknown conversion rate, DD is the data you observed, P(θ)P(\theta) is the prior (what you believed before the test), P(D∣θ)P(D \mid \theta) is the likelihood (how probable the data is for a given rate), P(D)P(D) is the overall probability of the data, and P(θ∣D)P(\theta \mid D) is the posterior, your updated belief. Foundations: probability

With a Beta prior, the posterior for a conversion rate is again a Beta distribution:

θ∣D∼Beta(α0+k, β0+n−k)\theta \mid D \sim \text{Beta}(\alpha_0 + k,\ \beta_0 + n - k)

Here α0\alpha_0 and β0\beta_0 are the prior's parameters (α0=β0=1\alpha_0 = \beta_0 = 1 is a flat prior that treats every rate as equally likely), kk is the number of conversions and nn the number of visitors, so n−kn - k is the number who did not convert. Foundations: distributions

Worked example: a candle shop with modest traffic

Woodstown Candles (woodstowncandles.example) is an invented Waterford shop testing a new product page. Version A: 48 orders from 1,200 visitors (4.0%). Version B: 59 orders from 1,180 visitors (5.0%).

  1. Posteriors with a flat prior: A is Beta(49,1,153)\text{Beta}(49, 1{,}153), B is Beta(60,1,122)\text{Beta}(60, 1{,}122).
  2. Draw 400,000 samples from each and count how often B's draw beats A's: 88% of the time.
  3. Expected loss, the conversion rate you give up on average by picking wrong: about 0.05 percentage points if you choose B, 1.05 points if you choose A.
  4. The relative uplift of B has a 95% credible interval from minus 14% to plus 81%.

A classical two proportion test gives z=1.18z = 1.18 and p=0.24p = 0.24, "not significant". Both say the evidence is thin, but the Bayesian reading is one you can act on: B is probably better and shipping it risks little.

import random

def prob_b_better(conv_a, n_a, conv_b, n_b, draws=400_000, seed=42):
    rng = random.Random(seed)
    wins = 0
    for _ in range(draws):
        a = rng.betavariate(1 + conv_a, 1 + n_a - conv_a)
        b = rng.betavariate(1 + conv_b, 1 + n_b - conv_b)
        wins += b > a
    return wins / draws

print(prob_b_better(48, 1200, 59, 1180))  # about 0.88

Peeking is not free in either school

The original article said a Bayesian test lets you peek at any time without raising false positives. That needs correcting. For classical tests, Evan Miller shows that checking repeatedly and stopping at the first significant result can push the false positive rate to 26.1% instead of 5%.4 David Robinson's simulations show that a Bayesian test stopped once expected loss falls below a threshold is not immune either: its error rates depend on the stopping rule.5 Fix the stopping rule before the test starts, whichever school you use.

Bandits move traffic to the winner while the test runs

An A/B test splits traffic evenly to the end, so many visitors keep seeing the weaker version. A multi armed bandit shifts traffic towards the better version as evidence builds up, balancing exploration (trying versions) with exploitation (showing the best so far). The name comes from slot machines, the one armed bandits.

Thompson sampling, first described by William R. Thompson in 1933, is the standard way to do it.67 Each version keeps a Beta distribution for its rate, as in the Bayesian test. For each visitor:

θ~i∼Beta(αi,βi),j=arg⁡max⁡iθ~i\tilde{\theta}_i \sim \text{Beta}(\alpha_i, \beta_i), \qquad j = \arg\max_i \tilde{\theta}_i

Here ii numbers the versions, αi\alpha_i is version ii's conversions plus 1, βi\beta_i its non conversions plus 1, θ~i\tilde{\theta}_i is one random draw from its Beta distribution, and jj is the version with the highest draw, which this visitor sees. After the visit, αj\alpha_j goes up by 1 on a conversion and βj\beta_j goes up by 1 otherwise. Foundations: distributions Uncertain versions still win some draws, clearly worse ones soon stop.

Worked example: three versions, 10,000 visitors

Three invented page versions with true conversion rates of 3%, 5% and 4%, which the algorithm does not know. Each run sends 10,000 visitors, and I averaged 300 simulated runs.

  1. An even split earns 10,000×(0.03+0.05+0.04)/3=40010{,}000 \times (0.03 + 0.05 + 0.04)/3 = 400 conversions on average.
  2. Thompson sampling earned 470 on average, 70 more.
  3. On average it sent about 7,700 visitors to the 5% version, 1,720 to the 4% version and 570 to the 3% version.

The price is precision about the losers. For a clean measurement of every version, run a test. For conversions while you learn, use a bandit.

import random

def thompson(true_rates, visitors, seed=0):
    rng = random.Random(seed)
    k = len(true_rates)
    alpha, beta, shown = [1] * k, [1] * k, [0] * k
    conversions = 0
    for _ in range(visitors):
        draws = [rng.betavariate(alpha[i], beta[i]) for i in range(k)]
        j = draws.index(max(draws))
        shown[j] += 1
        if rng.random() < true_rates[j]:
            alpha[j] += 1
            conversions += 1
        else:
            beta[j] += 1
    return conversions, shown

print(thompson([0.03, 0.05, 0.04], 10_000))

Attribution and mix models answer different questions

Attribution asks which touchpoint gets the credit for one conversion, bottom up from tracked journeys. Marketing mix modelling (MMM) asks how much each channel added to total sales, top down with regression on weekly totals, and tracks no individuals.

Worked example: one journey, five answers

An invented customer touches Paid Search, Email, Social, Direct and Retargeting, in that order, then orders for €100.

ModelPaid SearchEmailSocialDirectRetargeting
Last click€0€0€0€0€100
First click€100€0€0€0€0
Linear€20€20€20€20€20
Time decay (halving)€3.23€6.45€12.90€25.81€51.61
Position based (40, 20, 40)€40€6.67€6.67€6.67€40

Time decay here halves the weight for each step back: the weights are 116,18,14,12,1\tfrac{1}{16}, \tfrac{1}{8}, \tfrac{1}{4}, \tfrac{1}{2}, 1, which add up to 1.9375, so Retargeting gets 100/1.9375=51.61100 / 1.9375 = 51.61 euro. Same journey, five budgets.

Two corrections to the original article. Google no longer supports first click, linear, time decay or position based models in Google Ads, and removed them from Google Analytics 4 in November 2023, leaving data driven and last click. GA4 also gives direct visits no credit unless the whole path is direct.89 And "cookies are dying" needs care: Safari has blocked third party cookies by default since 2020,10 but Google said in April 2025 it would keep them in Chrome under user choice.11 The pressure on attribution is consent and browser privacy, not a switch off date. That is why mix models are back, with open source tools from Google (Meridian) and Meta (Robyn).1213 At its core, a mix model is a regression:

yt=β0+∑k=1Kβkxk,t+εty_t = \beta_0 + \sum_{k=1}^{K} \beta_k x_{k,t} + \varepsilon_t

Here yty_t is revenue in week tt, β0\beta_0 is the base revenue you would get with no marketing, xk,tx_{k,t} is spend on channel kk in week tt, βk\beta_k is the revenue each euro on channel kk returns, KK is the number of channels, and εt\varepsilon_t is everything the model does not explain. Real models add carry over (adstock), saturation and seasonality. Foundations: regression

Worked example: reading a mix model

An invented Galway homeware retailer fits the model on two years of weekly data and gets a base of €200,000 a week and returns of €2.50 per euro on TV, €4.00 on digital, €3.00 on social and €1.50 on print. A week with €30,000 TV, €17,500 digital, €8,500 social and €4,500 print predicts:

200,000+2.5×30,000+4.0×17,500+3.0×8,500+1.5×4,500=377,250200{,}000 + 2.5 \times 30{,}000 + 4.0 \times 17{,}500 + 3.0 \times 8{,}500 + 1.5 \times 4{,}500 = 377{,}250

So y^=377,250\hat{y} = 377{,}250 euro. Digital looks best, but these are average returns. The next euro may return much less, which is why real models add saturation curves. Foundations: marginal versus average

Power laws mean your average customer does not exist

Customer value is usually skewed: a few large customers bring a large share of revenue. A power law describes that, with the chance of a value above xx falling off as a power of xx:

P(X>x)∝x−αP(X > x) \propto x^{-\alpha}

Here XX is one customer's value, xx is a threshold in euro, α\alpha is the shape (smaller means a heavier tail and more extreme customers) and ∝\propto means "proportional to". It shrinks far slower than a normal distribution, so very large customers are much more common than a bell curve suggests. Foundations: distributions

The Pareto distribution is the standard example:14

f(x)=α xmαxα+1,x≥xmf(x) = \frac{\alpha\, x_m^{\alpha}}{x^{\alpha + 1}}, \qquad x \ge x_m

Here f(x)f(x) is the density at value xx, xmx_m is the smallest possible value and α\alpha the shape as before. For α>1\alpha > 1 the mean is αxm/(α−1)\alpha x_m / (\alpha - 1). Foundations: distributions

Its Lorenz curve gives the share of revenue that comes from the top share of customers:14

H(p)=p 1−1/αH(p) = p^{\,1 - 1/\alpha}

Here pp is the top share of customers (0.01 for the top 1%), α\alpha is the shape from above, and H(p)H(p) is the share of total revenue they bring. Foundations: distributions

Worked example: Pareto customers with a €50 floor

Assume, for the example, customer values follow a Pareto distribution with xm=50x_m = 50 euro and α=1.5\alpha = 1.5.

  1. Mean: 1.5×50/0.5=1501.5 \times 50 / 0.5 = 150 euro. Median: 50×21/1.5=7950 \times 2^{1/1.5} = 79 euro. The mean is almost twice the typical customer.
  2. The exponent: 1−1/1.5=1/31 - 1/1.5 = 1/3.
  3. Top 1%: 0.011/3=0.2150.01^{1/3} = 0.215, so 21.5% of revenue. Top 10%: 46.4%. Top 20%: 58.5%.
  4. Half the revenue comes from the top 0.53=12.5%0.5^{3} = 12.5\% of customers.

Revenue share of the top customersWith a Pareto shape of 1.5, the top 1% of customers bring 21.5% of revenue, the top 10% bring 46.4%, the top 20% bring 58.5% and the top half bring 79.4%.Share of revenue from the top customers (Pareto, shape 1.5)025507510021.5Top 1%46.4Top 10%58.5Top 20%79.4Top 50%Share of revenue in %Top share of customers

The horizontal axis is the top share of customers, the vertical axis their share of revenue. With this shape, a fifth of customers bring well over half the revenue, so that fifth deserves its own retention budget and CAC limit.

The original article said 1% of customers "often" drive 50% of revenue. I could not source that as a general rule, and the formula shows how extreme it is: it needs a shape of about 1.18. Measure your own, and estimate α\alpha by maximum likelihood, not with a straight line through a log log plot, which Clauset, Shalizi and Newman show can be badly wrong.15

Price elasticity tells you whether a price rise pays

Raise the price by 10% and some customers leave. Whether it is 5% or 20% decides whether revenue rises. Price elasticity of demand puts a number on that.16 The regression side is in modelling demand and price elasticity with regression, and dynamic pricing with AI shows where it leads.

ε=%ΔQ%ΔP\varepsilon = \frac{\%\Delta Q}{\%\Delta P}

Here ε\varepsilon is the elasticity, %ΔQ\%\Delta Q the percentage change in quantity sold and %ΔP\%\Delta P the percentage change in price. It is usually negative. If ∣ε∣>1|\varepsilon| > 1, demand is elastic and a price rise lowers revenue. If ∣ε∣<1|\varepsilon| < 1, it is inelastic and a rise increases revenue. Foundations: elasticity

At a single point on the demand curve:

ε=dQdP×PQ\varepsilon = \frac{dQ}{dP} \times \frac{P}{Q}

Here dQ/dPdQ/dP is the slope of the demand curve, and PP and QQ are the current price and quantity. For a straight line demand curve Q=a−bPQ = a - bP, the slope is −b-b, so ε=−bP/(a−bP)\varepsilon = -bP/(a - bP), where aa is the quantity at a price of zero and bb the units lost per euro. Foundations: elasticity

Worked example: a 10% rise for a bookkeeping app

Ledgerly (ledgerly.example) is an invented Kilkenny bookkeeping app with 1,000 customers at €99 a month. It considers €108.90, a 10% rise. Revenue changes by 1.1×(1+0.1 ε)−11.1 \times (1 + 0.1\,\varepsilon) - 1:

ElasticityCustomersRevenue
−0.5-0.5minus 5%plus 4.5%
−1.0-1.0minus 10%minus 1.0%
−1.5-1.5minus 15%minus 6.5%
−2.5-2.5minus 25%minus 17.5%

A correction to the original: at exactly −1-1 revenue stays flat only for a tiny change. For a 10% step it falls 1%, because 1.1×0.9=0.991.1 \times 0.9 = 0.99.

Now suppose Ledgerly's demand is the straight line Q=2,000−10PQ = 2{,}000 - 10P. At €99: Q=2,000−990=1,010Q = 2{,}000 - 990 = 1{,}010 and ε=−10×99/1,010=−0.98\varepsilon = -10 \times 99 / 1{,}010 = -0.98. Revenue is highest where elasticity is exactly −1-1, at P=a/(2b)=2,000/20=100P = a/(2b) = 2{,}000/20 = 100 euro. So €99 is close to the revenue maximum, and a 10% rise would overshoot.

From elasticity to a price

The original article gave ΔP/P=1/(∣ε∣−1)\Delta P / P = 1/(|\varepsilon| - 1) as the revenue maximising price change. That formula is wrong: with constant elasticity above 1, every price rise lowers revenue. What does hold, when you know marginal cost, is the markup rule for maximum profit, the Lerner index:17

P−MCP=1∣ε∣⟺P∗=MC×∣ε∣∣ε∣−1\frac{P - MC}{P} = \frac{1}{|\varepsilon|} \quad\Longleftrightarrow\quad P^{*} = MC \times \frac{|\varepsilon|}{|\varepsilon| - 1}

Here PP is the price, MCMC the marginal cost of serving one more customer, ∣ε∣|\varepsilon| the size of the elasticity (it must be above 1), and P∗P^{*} the profit maximising price. Foundations: marginal versus average

An example: marginal cost €20 a month and elasticity −1.5-1.5 give P∗=20×1.5/0.5=60P^{*} = 20 \times 1.5 / 0.5 = 60 euro. Check: (60−20)/60=0.667=1/1.5(60 - 20)/60 = 0.667 = 1/1.5.

From your own price history, elasticity is the slope of a log log regression. Foundations: logarithms

import math

def elasticity(prices, quantities):
    lp = [math.log(p) for p in prices]
    lq = [math.log(q) for q in quantities]
    mp, mq = sum(lp) / len(lp), sum(lq) / len(lq)
    num = sum((x - mp) * (y - mq) for x, y in zip(lp, lq))
    den = sum((x - mp) ** 2 for x in lp)
    return num / den

Asking customers instead: the Van Westendorp meter

When you have no price history, Peter van Westendorp's Price Sensitivity Meter (1976) asks four questions: at what price would it be so low you doubt the quality, a bargain, getting expensive, and too expensive to consider.18 Where the cumulative curves cross gives a range of acceptable prices: "too low" against "not a bargain" marks the bottom, "too expensive" against "not expensive" the top. It measures what people say, not what they do, so test the range. The psychology side is in pricing psychology.

Retention compounds into profit

The most quoted number in retention comes from Frederick Reichheld and Earl Sasser in 1990: across the service businesses they studied, reducing customer defections by 5% boosted profits by 25% to 85%.19 The figure later quoted from Reichheld's work at Bain is 25% to 95%.20 Their explanation: acquisition is paid once, purchases grow, operating costs fall, and loyal customers refer others (referrals are their own article).19

Two cautions. The numbers come from specific industries in 1990, so read them as "large", not as a forecast. And "5%" is ambiguous, as the example shows.

The value of better retention, with discounting:

ΔLTV=∑t=0TM(rnew t−rold t)(1+d)t\Delta LTV = \sum_{t=0}^{T} \frac{M \left(r_{\text{new}}^{\,t} - r_{\text{old}}^{\,t}\right)}{(1+d)^{t}}

Here ΔLTV\Delta LTV is the gain in lifetime value per customer, tt counts periods from 0 to the horizon TT, MM is the gross profit per period (ARPU×mARPU \times m), roldr_{\text{old}} and rnewr_{\text{new}} are the retention rates before and after, so rtr^{t} is the chance a customer is still there in period tt, and dd is the discount rate per period. Foundations: discounting

Without discounting and with no horizon, it simplifies to:

ΔLTV=M(11−rnew−11−rold)\Delta LTV = M \left(\frac{1}{1 - r_{\text{new}}} - \frac{1}{1 - r_{\text{old}}}\right)

Here MM is the gross profit per period and 1/(1−r)1/(1 - r) is the expected lifetime in periods for a retention rate rr. The original version left out the margin. Foundations: lifetime value

Worked example: why the range is so wide

An invented subscription with €100 ARPU, 80% margin, so M=80M = 80 euro a month, and €400 CAC.

  1. At 5% churn: LTV=80/0.05=1,600LTV = 80 / 0.05 = 1{,}600 euro, profit per customer 1,600−400=1,2001{,}600 - 400 = 1{,}200.
  2. Churn falls by 5% of itself, to 4.75%: LTV=80/0.0475=1,684LTV = 80 / 0.0475 = 1{,}684, profit 1,284. That is plus 7%.
  3. Churn falls by one point, to 4%: LTV=2,000LTV = 2{,}000, profit 1,600. Plus 33%.
  4. Start instead at 10% churn and cut five points to 5%: LTVLTV goes from 800 to 1,600 and profit from 400 to 1,200. Plus 200%.

The same "5%" means plus 7% or plus 200%. The fixed CAC is the lever: LTV from €800 to €1,000 with €400 CAC takes profit from €400 to €600, plus 50% from plus 25% LTV.

Lifetime value against monthly retentionWith €80 monthly gross profit per customer, lifetime value rises from €800 at 90% retention to €8,000 at 99% retention, and the curve gets steeper the closer retention gets to 100%.Lifetime value by monthly retention (€80 gross profit a month)€0€2,500€5,000€7,500€10,00090%92%94%95%96%97%98%99%Lifetime value in euro€Monthly retention

The horizontal axis is monthly retention, the vertical axis undiscounted lifetime value. The takeaway is the shape: from 95% to 97% retention, lifetime value goes from €1,600 to €2,667, plus 67% for two points. Each point is worth more than the last.

Discounted at 10% a year over 60 months, the same customer is worth €1,351 at 95% retention and €1,591 at 96%. Discounting shrinks the numbers, not the shape.

Maths is not optional

LTV to CAC says whether growth pays, payback whether you can afford it. Cohorts and survival curves show what averages hide. Bayesian tests and bandits turn experiments into decisions. Attribution credits journeys, mix models credit channels. Power laws make the average customer a fiction, elasticity decides whether a price rise pays, and retention compounds.

I have applied every concept here across eCommerce, SaaS and B2B products. It is the working toolkit I use to make decisions about millions in marketing spend and product investment. Start with the one number your next decision depends on.

Footnotes

  1. David Skok, SaaS Metrics 2.0: A Guide to Measuring and Improving What Matters, For Entrepreneurs, https://www.forentrepreneurs.com/saas-metrics-2/

  2. Cameron Davidson-Pilon and lifelines contributors, Introduction to survival analysis (survival function, hazard function, censoring), lifelines documentation, https://lifelines.readthedocs.io/en/latest/Survival%20Analysis%20intro.html

  3. Cameron Davidson-Pilon and lifelines contributors, Survival analysis with lifelines (Kaplan Meier estimate, log rank test), lifelines documentation, https://lifelines.readthedocs.io/en/latest/Survival%20analysis%20with%20lifelines.html

  4. Evan Miller, How Not To Run an A/B Test, 2010, https://www.evanmiller.org/how-not-to-run-an-ab-test.html

  5. David Robinson, Is Bayesian A/B Testing Immune to Peeking? Not Exactly, Variance Explained, 2015, http://varianceexplained.org/r/bayesian-ab-testing/

  6. Wikipedia, Thompson sampling (history: William R. Thompson, Biometrika, 1933), https://en.wikipedia.org/wiki/Thompson_sampling

  7. Daniel Russo, Benjamin Van Roy, Abbas Kazerouni, Ian Osband and Zheng Wen, A Tutorial on Thompson Sampling, Foundations and Trends in Machine Learning 11(1), 2018, https://arxiv.org/abs/1707.02038

  8. Google, About attribution models, Google Ads Help, https://support.google.com/google-ads/answer/6259715

  9. Google, Get started with attribution (attribution models), Google Analytics Help, https://support.google.com/analytics/answer/10596866

  10. John Wilander, Full Third Party Cookie Blocking and More, WebKit blog, 24 March 2020, https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/

  11. Anthony Chavez, Next steps for Privacy Sandbox and tracking protections in Chrome, Google Privacy Sandbox, 22 April 2025, https://privacysandbox.google.com/blog/privacy-sandbox-next-steps

  12. Google, Meridian, an open source marketing mix model, Google for Developers, https://developers.google.com/meridian

  13. Meta Marketing Science, Robyn, an open source marketing mix modelling package, https://facebookexperimental.github.io/Robyn/

  14. Wikipedia, Pareto distribution (density, mean, Lorenz curve), https://en.wikipedia.org/wiki/Pareto_distribution

  15. Aaron Clauset, Cosma Rohilla Shalizi and M. E. J. Newman, Power-law distributions in empirical data, SIAM Review 51(4), 2009, https://arxiv.org/abs/0706.1062

  16. OpenStax, Principles of Economics 3e, 5.1 Price Elasticity of Demand and Price Elasticity of Supply, https://openstax.org/books/principles-economics-3e/pages/5-1-price-elasticity-of-demand-and-price-elasticity-of-supply

  17. Wikipedia, Lerner index (Abba Lerner, 1934), https://en.wikipedia.org/wiki/Lerner_index

  18. Wikipedia, Van Westendorp's Price Sensitivity Meter, https://en.wikipedia.org/wiki/Van_Westendorp%27s_Price_Sensitivity_Meter

  19. Frederick F. Reichheld and W. Earl Sasser Jr., Zero Defections: Quality Comes to Services, Harvard Business Review, September to October 1990, https://hbr.org/1990/09/zero-defections-quality-comes-to-services

  20. Amy Gallo, The Value of Keeping the Right Customers, Harvard Business Review, 2014, https://hbr.org/2014/10/the-value-of-keeping-the-right-customers

If you have a lifetime value or a churn number you do not quite trust, bring it to the free workshop. We pick the one decision it should drive, then I spend two weeks of real work on me building the model behind it.