Where Streaks Break: The Hazard Rate Behind Daily Engagement Mechanics
Day 1 saves the most users. It also costs 12.7 times more per user saved than day 29. Both are true, and your budget decides which one matters. The hazard-rate model for streaks, with the Python and the counterintuitive answer.
Table of contents
A streak is a sequence of options with a rising exercise probability. A user on day 20 is a fundamentally different risk than a user on day 1, and the reward schedule should reflect that. Most do not, because most are designed around round numbers rather than around where users actually leave.
The short answer
Streak drop-off is governed by a hazard rate that starts high and falls as the surviving population self-selects. Placing a reward on day 1 produces the most additional long-run survivors in absolute terms. It also costs 12.7 times more per survivor than the same reward on day 29, because on day 1 you are paying every single user in the cohort. Under a fixed budget the answer inverts completely.
Modelling continuation, not retention
Retention curves tell you how many users are left. Hazard rates tell you the probability a user who is here today is still here tomorrow, and that is the quantity you can actually influence with a reward.
Streak hazards have a characteristic shape: continuation probability is lowest at the start and rises toward an asymptote. Someone who has kept a streak for three weeks has demonstrated something about themselves that someone on day 2 has not.
Model it as continuation probability p(d) rising exponentially toward a ceiling:
p(d) = p_inf - (p_inf - p_1) x exp(-k(d - 1))
With p_1 = 0.55, p_inf = 0.95 and k = 0.35, a 10,000-user cohort behaves like this:
| Day | p(continue) | Users active | Users lost that day |
|---|---|---|---|
| 1 | 0.5500 | 10,000 | 4,500 |
| 2 | 0.6681 | 5,500 | 1,825 |
| 3 | 0.7514 | 3,675 | 914 |
| 5 | 0.8514 | 2,237 | 332 |
| 7 | 0.9010 | 1,677 | 166 |
| 14 | 0.9458 | 995 | 54 |
| 21 | 0.9496 | 686 | 35 |
| 30 | 0.9500 | 432 | n/a |
Forty five percent of the cohort never reaches day 2. By day 7 you have 16.8% left. The day-30 survivor count is 432 out of 10,000.
The question everyone asks wrong
"Where should we put the reward?" has no answer until you say what you are optimising and what you are spending.
Suppose a reward costs $2 per user who receives it, and lifts that day's continuation probability by 10 percentage points. Two obvious objectives give opposite answers.
| Reward day | Users paid | Spend | Extra day-30 survivors | Cost per survivor |
|---|---|---|---|---|
| 1 | 10,000 | $20,000 | 78.5 | $254.87 |
| 2 | 5,500 | $11,000 | 64.6 | $170.29 |
| 3 | 3,675 | $7,349 | 57.4 | $127.95 |
| 5 | 2,237 | $4,473 | 50.7 | $88.24 |
| 7 | 1,677 | $3,353 | 47.9 | $70.00 |
| 14 | 995 | $1,991 | 45.6 | $43.63 |
| 21 | 686 | $1,371 | 45.4 | $30.17 |
| 29 | 454 | $909 | 45.4 | $20.00 |
Day 1 produces the most extra survivors: 78.5 on a baseline of 431.6, an 18.2% lift. Day 29 produces 45.4 extra survivors for $909 instead of $20,000.
Day 1 costs 12.7 times more per survivor than day 29. Both columns are correct. The tension is real, and it is not resolved by picking a favourite metric.
What a budget does to the answer
Give the same programme a fixed $2,000 and the ranking inverts.
| Reward day | Users you can afford to reward | Extra day-30 survivors |
|---|---|---|
| 1 | 1,000 | 7.8 |
| 3 | 1,000 | 15.6 |
| 7 | 1,000 | 28.6 |
| 14 | 995 | 45.6 |
| 21 | 686 | 45.4 |
| 29 | 454 | 45.4 |
At $2,000 you can only reach 1,000 users. Spending them on day 1 buys 7.8 survivors. Spending them on day 14 buys 45.6, nearly six times more, and costs less because there are fewer than 1,000 users left to pay.
The reason is that a day-1 reward is mostly wasted on users who were about to churn regardless, and a day-14 reward lands on a population that has already proven it will probably continue. You are buying a cheaper marginal probability from a more reliable customer.
The model
import math
def streak_analysis(cohort=10_000, p1=0.55, p_inf=0.95, k=0.35,
horizon=30, lift=0.10, reward_cost=2.00, budget=None):
def p_cont(day):
return p_inf - (p_inf - p1) * math.exp(-k * (day - 1))
surv = [1.0]
for d in range(1, horizon):
surv.append(surv[-1] * p_cont(d))
def tail(frm, to):
q = 1.0
for d in range(frm, to):
q *= p_cont(d)
return q
rows = []
for d in range(1, horizon):
at_risk = cohort * surv[d - 1]
reached = at_risk if budget is None else min(at_risk, budget / reward_cost)
saved = reached * lift * tail(d + 1, horizon)
spend = reached * reward_cost
rows.append((d, reached, spend, saved, spend / saved if saved else float("inf")))
return rows, cohort * surv[horizon - 1]
rows, baseline = streak_analysis()
print(f"baseline day-30 survivors: {baseline:,.1f}\n")
print(f"{'day':>4} {'paid':>9} {'spend':>10} {'extra':>8} {'$/survivor':>12}")
for d, paid, spend, saved, cps in rows:
if d in (1, 3, 7, 14, 21, 29):
print(f"{d:>4} {paid:>9,.0f} {spend:>10,.0f} {saved:>8.1f} {cps:>12,.2f}")
Output:
baseline day-30 survivors: 431.6
day paid spend extra $/survivor
1 10,000 20,000 78.5 254.87
3 3,675 7,349 57.4 127.95
7 1,677 3,353 47.9 70.00
14 995 1,991 45.6 43.63
21 686 1,371 45.4 30.17
29 454 909 45.4 20.00
Pass a budget argument to see the inversion.
Fitting this to your product
The three parameters are estimable from data you already have. p_1 is your day-1 to day-2 continuation rate. p_inf is the continuation rate among long-streak users, which flattens out and is easy to read off. k controls how fast you get from one to the other, and one line of curve fitting or a manual sweep will find it.
Then the decision becomes concrete rather than aesthetic. If you are unconstrained and optimising raw retained users, reward early. If you have a budget, which you do, reward where the surviving population is dense enough to be worth paying and sparse enough to be affordable.
The mistake worth avoiding is the default: a reward at day 7 because a week is a familiar unit. Day 7 is neither the best total nor the best efficiency in this model. It is a round number, and round numbers are where unpriced mechanics go.
Leaderboards have the same problem in a different shape. The default design shows every player a ranked list, and for most of them that list is a daily notification that they cannot win.
Get the Promo & Bonus Economics Workbook
Every formula for pricing a promo before you launch it: expected value, wagering cost, breakage, breakeven conversion. Worked examples with real executed numbers.
Browse all free guides →Want to implement this with guidance?
Santosh helps founders turn insights like this into real systems.
External Resources
Further Reading & Tools
Investopedia — Financial Engineering
Reference on the field, its three pillars, and its primary applications
CFA Institute — Refresher Readings
Curriculum material on derivatives valuation, probability, and risk measurement
QuantLib
Open-source quantitative finance library, reference for how pricing models are structured
arXiv q-fin
Preprints in quantitative finance covering pricing, risk management, and market microstructure