Retention¶
Retention analysis from the Tidemill engine.
Revenue retention (NRR / GRR)¶
- NRR (Net Revenue Retention) = (start MRR + expansion - contraction - churn) / start MRR
- NRR > 100% means expansion outpaces churn
- GRR (Gross Revenue Retention) = (start MRR - contraction - churn) / start MRR
- GRR is always <= 100% (ignores expansion)
Cohort retention¶
Customers are grouped into cohorts by the month they first became
active. For each cohort, the share still active M0, M1, ... Mn
months later is reported — a triangular matrix showing how cohorts
decay (or retain) over time.
In [6]:
Copied!
from tidemill import reports
from tidemill.reports.client import TidemillClient
reports.setup()
START, END = "2025-07-01", "2026-04-30"
tm = TidemillClient()
from tidemill import reports
from tidemill.reports.client import TidemillClient
reports.setup()
START, END = "2025-07-01", "2026-04-30"
tm = TidemillClient()
1. Cohort retention¶
Customers grouped by the month they first became active, then
tracked forward. Each column Mn is the fraction of that cohort
still active n months after joining. M0 is always 100%.
In [7]:
Copied!
coh = reports.retention.cohort(tm, START, END)
reports.retention.style_cohort(coh)
coh = reports.retention.cohort(tm, START, END)
reports.retention.style_cohort(coh)
Out[7]:
| cohort_size | M0 | M1 | M2 | M3 | M4 | M5 | M6 | M7 | M8 | M9 | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| cohort_month | |||||||||||
| Jul 2025 | 21 | 1.000000 | 0.809524 | 0.714286 | 0.761905 | 0.761905 | 0.761905 | 0.714286 | 0.714286 | 0.714286 | 0.714286 |
| Aug 2025 | 4 | 1.000000 | 0.750000 | 0.750000 | 0.750000 | 0.750000 | 0.750000 | 0.750000 | 0.750000 | 0.750000 | nan |
| Sep 2025 | 0 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan |
| Oct 2025 | 8 | 1.000000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | 0.500000 | nan | nan | nan |
| Nov 2025 | 0 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan |
| Dec 2025 | 7 | 1.000000 | 0.285714 | 0.285714 | 0.285714 | 0.285714 | nan | nan | nan | nan | nan |
| Jan 2026 | 5 | 1.000000 | 0.600000 | 0.600000 | 0.600000 | nan | nan | nan | nan | nan | nan |
| Feb 2026 | 0 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan |
| Mar 2026 | 0 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan |
| Apr 2026 | 0 | nan | nan | nan | nan | nan | nan | nan | nan | nan | nan |
In [8]:
Copied!
reports.retention.plot_cohort(coh)
reports.retention.plot_cohort(coh)
2. Monthly NRR and GRR¶
Net Revenue Retention and Gross Revenue Retention per month from the Tidemill API.
- NRR = (start MRR + expansion - contraction - churn) / start MRR
- GRR = (start MRR - contraction - churn) / start MRR
NRR > 100% means expansion outpaces churn. GRR is always <= 100%.
In [9]:
Copied!
rr = reports.retention.nrr_grr(tm, START, END)
reports.retention.style_nrr_grr(rr)
rr = reports.retention.nrr_grr(tm, START, END)
reports.retention.style_nrr_grr(rr)
Out[9]:
| nrr | grr | |
|---|---|---|
| month | ||
| Jul 2025 | nan% | nan% |
| Aug 2025 | 97.8% | 91.7% |
| Sep 2025 | 82.7% | 82.7% |
| Oct 2025 | 97.6% | 95.3% |
| Nov 2025 | 96.0% | 82.0% |
| Dec 2025 | 97.9% | 97.9% |
| Jan 2026 | 90.6% | 90.6% |
| Feb 2026 | 96.3% | 96.3% |
| Mar 2026 | 100.0% | 100.0% |
| Apr 2026 | 100.0% | 100.0% |
In [10]:
Copied!
reports.retention.plot_nrr_grr(rr)
reports.retention.plot_nrr_grr(rr)
In [ ]:
Copied!