The cohort table: how to read it
O que você vai aprender
- read a table: rows are cohorts, columns are age (D0/D1/D7/D30)
- tell absolute time (the calendar) from cohort age — and see where the diagonal lives in the table
- understand why the table is triangular and what the empty cells mean
- compare generations: reading a column down versus a row across
- do a first heatmap read in under a minute
One cohort is a row. Many cohorts make a table
In the previous lesson we computed for one . One cohort is one row of numbers. Stack every cohort of the product one under another and you get a cohort table — the main instrument through which an analyst looks at retention.
The layout is simple and always the same:
- a row = a cohort, everyone who arrived for the first time on the same day (or in the same week);
- a column = the cohort's age: D0, D1, D7, D14, D30;
- a cell = how many of that cohort were active at that age — in absolutes or as a percentage of the cohort size.
Here is Kotomarket's black box, weekly cohorts, today is March 14. First in absolutes:
| cohort | size (D0) | D1 | D7 | D14 | D30 |
|---|---|---|---|---|---|
| Feb 1 | 1,200 | 456 | 168 | 120 | 84 |
| Feb 8 | 1,400 | 518 | 182 | 126 | 84 |
| Feb 15 | 1,300 | 468 | 156 | 104 | — |
| Feb 22 | 1,500 | 525 | 165 | 105 | — |
| Mar 1 | 1,600 | 528 | 176 | — | — |
| Mar 8 | 1,500 | 480 | — | — | — |
Rows of absolutes cannot be compared: the cohorts differ in size. So the table is almost always converted to percentages — each cell divided by the size of ITS OWN cohort (the fixed denominator from the previous lesson):
| cohort | size | D1 | D7 | D14 | D30 |
|---|---|---|---|---|---|
| Feb 1 | 1,200 | 38% | 14% | 10% | 7% |
| Feb 8 | 1,400 | 37% | 13% | 9% | 6% |
| Feb 15 | 1,300 | 36% | 12% | 8% | — |
| Feb 22 | 1,500 | 35% | 11% | 7% | — |
| Mar 1 | 1,600 | 33% | 11% | — | — |
| Mar 8 | 1,500 | 32% | — | — | — |
The size column always stays: without it the percentages hang in the air — exactly as in the lesson about denominators.
Absolute time versus cohort age
The most important idea of this lesson: a table contains two different times, and they are constantly confused.
Cohort age lives in the columns. Moving right along a row is moving through one group's life: day one, day seven, day thirty.
Absolute time (the calendar) lives in the rows: the lower the row, the later the cohort arrived. But a calendar date inside the table lives in neither a column nor a row — it runs along a diagonal.
Check it on March 1. For the March 1 cohort that is D0. For the February 22 cohort it is D7 (Feb 22 + 7 days). For February 15 it is D14. For February 1 it is D28. One calendar date has cut diagonally across the whole table:
D0 D1 D7 D14 D30
Feb 1 · · · · · ↖
Feb 8 · · · · · ↖ a diagonal =
Feb 15 · · · [Mar 1] · ↖ one calendar
Feb 22 · · [Mar 1] · · ↖ date
Mar 1 [Mar 1] · · · · ↖
Why this matters. Events of the outside world — a release, a tracking outage, a holiday, an ad launch — happen on a specific calendar date and therefore leave a trace along a diagonal, not down a column. If event collection broke on March 1, the D0 cell of the March cohort sags, the D7 cell of the February 22 cohort sags, the D14 cell of an older one sags — and in the D7 column it will look like "one weird cohort", although the problem was shared and lasted a day.
Changes to the product itself — a new onboarding, a different price — affect entire fresh cohorts, that is, they show up in the lower rows. Telling those two patterns apart is half the craft of reading cohort tables.
Why the table is triangular
Look at the shape: the filled part of the table is a triangle, and the lower-right corner is empty. That is not lost data or a broken export.
The reason is exactly the one from the previous lesson: young have not lived the older ages yet. Today is March 14, therefore:
- the March 8 cohort only has D1 (March 9). Its D7 arrives on March 15 — tomorrow;
- the March 1 cohort has D1 and D7, while its D14 falls on March 15;
- the February 15 cohort will reach D30 only on March 17.
The lower the row, the shorter its filled tail. Hence the triangle — and hence the rule:
A column is compared only across rows where the cell is filled. An empty cell means "not known yet", not "zero".
The mistake nearly everyone makes when first building such a table: computing "average D30 across all cohorts". The empty cells either turn into zeros (the average collapses and a nonexistent drop appears) or silently drop out — and then the average is computed over old cohorts only and presented as the overall figure.
There is an opposite bias too: looking only at mature cohorts hides fresh data entirely, and a problem gets noticed a month later than it could have been. So in practice: read the early marks (D1, D7) across all cohorts including the fresh ones, and the late ones (D30) only across mature cohorts. D1 and D7 mature quickly and are the first to show that new generations have got worse.
How to read it: a row across, a column down
A table has exactly two reading directions, and they answer different questions.
A row across — the life of one cohort. 38% → 14% → 10% → 7%. You see the shape of the curve: a sharp fall between D1 and D7, then flattening. Nearly every product behaves this way: most newcomers drop off in the first days, while those who survive to the second week leave far more slowly. If the curve reaches a plateau, the product has a core that stays. If it keeps sliding towards zero, there is no core.
A column down — comparing generations at the same age. This is the most valuable movement, because it compares like with like: everyone at exactly seven days old.
column D1: 38% → 37% → 36% → 35% → 33% → 32%
column D7: 14% → 13% → 12% → 11% → 11%
Six consecutive generations — and both columns creep downwards. That is no longer noise: each new generation retains worse than the one before. Meanwhile the size of the last cohort is larger than that of the first (1,200 → 1,500): more people arrive and a smaller share of them stays.
Entry #7 in L.'s journal: "Marketing celebrates DAU growth. I look at the D7 column of the new cohorts: 14, 13, 12, 11. We are pouring water into a leaky bucket and praising the tap."
A first heatmap read in one minute
Cohort tables are often coloured — darker means more, lighter means less. Such colouring is called a heatmap, and the eye reads it faster than digits. The order of a first read:
- Check the denominators — the first column with cohort sizes. A row of 40 people will jump by tens of percent because of one cat, and it cannot be compared with a row of a thousand.
- Look at the shape of a row — where the cliff is and where the plateau begins.
- Walk the columns down — are generations improving or degrading?
- Find anomalies. One odd row means something happened to that particular set of people (a traffic source, a promo). An odd diagonal means something happened on a specific calendar day (a release, an outage). An odd column usually points at the metric itself, or at that age landing on a weekend.
- Ignore the lower-right corner — it is empty not because things are bad there.
d1_pct, d7_pct and d30_pct.d7_feb and d7_mar as percentages, the difference in percentage points diff_pp, and the relative change diff_rel in percent. Note: in absolutes March looks better.Principais pontos
- table rows are cohorts, columns are age (D0/D1/D7/D30), a cell is an active count or a share of its own cohort size
- the table holds two times: age runs along columns, and in a full table with a uniform step a calendar date runs along a diagonal
- the table is triangular because young cohorts have not lived the older ages; empty ≠ zero
- a row across shows the shape of the curve; a column down compares generations at the same age
- anomalies: a row means something about that group of people, a diagonal means an event on one date, a column raises a question about the metric itself
Next — Case #0. You run the investigation: a six-step template, your own computations, your own verdict. L.'s debrief opens only afterwards.