Продуктовые метрики: AARRR, North Star, unit-экономика
В https://courses.digitable.life/post/product-management/01-discovery-and-research/ мы выясняли, существует ли проблема. Метрики отвечают на следующий вопрос: изменилось ли что-нибудь в реальности после того, как мы что-то сделали — и стоило ли это денег, которые мы потратили.
Это не «отчётность для руководства». Метрика — инструмент принятия решений в условиях, где твоё мнение о продукте систематически ошибается примерно в 2/3 случаев (Kohavi, Tang, Xu, «Trustworthy Online Controlled Experiments», 2020). Ниже — как выбрать числа, которые действительно управляют решениями, и как не построить красивый дашборд, по которому нельзя принять ни одного решения.
1. Что такое метрика по существу
1.1. Метрика — это сжатие с потерями
Реальность продукта — это миллионы событий: клики, сессии, платежи, отвалы, жалобы. Человек не может держать это в голове. Метрика сжимает поток событий в одно число, чтобы его можно было сравнить — с прошлой неделей, с контрольной группой, с планом.
Как у любого сжатия с потерями, у метрики есть артефакты. Число конверсия = 4.2%
не содержит информации о том, кто конвертировался, почему и что было с остальными 95.8%.
Отсюда главное правило: метрика нужна, чтобы заметить изменение, а не чтобы его объяснить.
Объясняют когорты, сегменты, качественные интервью и логи.
1.2. Критерии хорошей метрики
Алистер Кролл и Бенджамин Йосковиц в «Lean Analytics» (leananalyticsbook.com) формулируют четыре свойства:
| Свойство | Что значит | Плохой пример | Хороший пример |
|---|---|---|---|
| Сравнительная | есть с чем сопоставить | «12 000 регистраций» | «регистраций +18% нед./нед.» |
| Понятная | команда воспроизводит определение по памяти | «engagement score 7.4» | «доля пользователей, сделавших ≥3 заказа за 28 дней» |
| Отношение, а не счётчик | нормирована на базу, устойчива к росту трафика | «10 000 ошибок в день» | «0.3% сессий с ошибкой» |
| Меняющая поведение | из значения следует действие | «всего просмотров» | «время до первого успешного действия» |
Пятый критерий добавляю от себя, и он самый недооценённый: метрика должна быть воспроизводимой без разработчика. Если её нельзя посчитать SQL-запросом или в BI за пятнадцать минут, ей не будут пользоваться — а значит, она не существует.
1.3. Vanity metrics: почему «растёт вверх» — не аргумент
Эрик Рис ввёл термин vanity metrics — метрики тщеславия. Признак: число монотонно растёт по определению, потому что это накопительный счётчик. Всего зарегистрировано, всего скачано, всего просмотров с запуска — такие числа не могут упасть, значит, не несут информации о качестве продукта.
Проверка: «если это число вырастет вдвое, что я сделаю по-другому?» Если ответа нет — это украшение дашборда, а не метрика.
Отдельный подвид — метрики, которые «растут» из-за смены знаменателя. Классика: команда чистит базу от неактивных, конверсия в платящих подскакивает с 3% до 5%, все празднуют. Абсолютное число платящих при этом не изменилось.
1.4. Закон Гудхарта
«Когда мера становится целью, она перестаёт быть хорошей мерой» — формулировка Мэрилин Стратерн по мотивам работ Чарльза Гудхарта.
Любая метрика, за которую платят премию, будет оптимизирована — включая пути, которых вы не имели в виду. Примеры из практики:
- KPI «время ответа поддержки» → операторы отвечают шаблоном «принято в работу» за 30 секунд;
- KPI «количество установок» → закупается мотивированный трафик, retention D7 падает вдвое;
- KPI «DAU» → внедряются агрессивные пуши, DAU растёт неделю, отписки растут навсегда (закон паршивеющих CTR Эндрю Чена: The Law of Shitty Clickthroughs);
- KPI «средний чек» → команда отключает дешёвый тариф, чек растёт, выручка падает.
Единственная рабочая защита — guardrail-метрики (метрики-ограничители), которые двигаться не должны, и о них ниже, в разделе 8.
1.5. Leading и lagging
- Lagging (запаздывающие): выручка, MRR, годовой отток. Достоверны, но узнаёшь поздно — повлиять уже нельзя.
- Leading (опережающие): активация в первую неделю, частота ключевого действия, доля пользователей, добавивших второго участника команды. Шумны, но управляемы сейчас.
Продуктовая работа живёт в leading-метриках, финансовая отчётность — в lagging. Задача продакта — доказать связь между ними (см. дерево метрик в разделе 4), иначе леденящий вопрос «а вы уверены, что это влияет на деньги?» останется без ответа.
2. AARRR: пиратские метрики
Дэйв Макклюр в 2007 году предложил разбить жизнь пользователя на пять стадий — Startup Metrics for Pirates. Ценность фреймворка не в аббревиатуре, а в дисциплине: у каждой стадии свой узкий набор метрик, свои гипотезы и своя команда. Без этого разговор «надо растить продукт» превращается в спор без предмета.
метрики: визиты, CPC, CAC по каналам"] --> A2 A2["Activation — получил ценность
метрики: % дошедших до aha-момента, TTV"] --> R1 R1["Retention — вернулся
метрики: D1/D7/D30, WAU/MAU, кривая когорт"] --> R2 R2["Revenue — заплатил
метрики: конверсия в платный, ARPU, ARPPU, LTV"] --> Ref Ref["Referral — привёл других
метрики: k-фактор, доля инвайтов, viral cycle time"] -.обратная петля.-> T R1 -. отвал .-> D[Dormant / churn] D -. реактивация .-> R1 style A2 fill:#2f8f5b,color:#fff style R1 fill:#2f8f5b,color:#fff style D fill:#b04a3f,color:#fff
2.1. Acquisition — привлечение
Единственная метрика, которая здесь имеет смысл сама по себе, — CAC по каналу, и обязательно fully loaded: рекламный бюджет + зарплаты маркетинга и продаж + скидки и промокоды, делённые на число привлечённых клиентов того же периода.
CAC_канал = (spend + salaries + discounts) / new_customers
Типичная ошибка — считать «средний CAC по компании». Он бесполезен: органика стоит почти ноль и размывает картину платных каналов. Считайте по каналам и по когортам.
2.2. Activation — активация
Самая недооценённая стадия. Активация — это момент, когда пользователь впервые получил обещанную ценность, а не «завершил регистрацию». Формулируется как поведенческое событие:
- Facebook: 7 друзей за 10 дней (классический кейс, много раз пересказанный в блогах роста);
- Slack: команда обменялась 2000 сообщениями;
- Dropbox: положил хотя бы один файл хотя бы на одно устройство.
Как найти свой aha-момент: взять пользователей, доживших до D30, и пользователей, не доживших, и искать поведение в первые дни, которое их разделяет. Дальше — обязательно проверять причинность экспериментом, потому что корреляция «активные делают X» тривиально объясняется обратным направлением: активные делают всё, включая X (см. https://courses.digitable.life/post/product-management/05-mvp-and-experiments/).
Вторая метрика стадии — TTV (time to value): медиана времени от регистрации до первого ключевого действия. Это одна из немногих метрик, где медиана и перцентили обязательны — среднее уничтожается «спящими», которые вернулись через полгода.
2.3. Retention — удержание
Retention — фундамент. Если пользователи не возвращаются, привлечение = наливать воду в дырявое ведро: каждая новая когорта вытекает, рост требует всё больше денег и останавливается, когда бюджет упирается в потолок канала. Подробный разбор — раздел 5.
2.4. Revenue — деньги
Ключевые определения, которые путают чаще всего:
ARPU = выручка за период / ВСЕ активные пользователи
ARPPU = выручка за период / ТОЛЬКО платящие
C1 = платящие / все пользователи (конверсия в платящего)
следовательно: ARPU = C1 × ARPPU
Полезно всегда держать все три: рост ARPU может быть вызван и ростом конверсии (хорошо, база расширяется), и ростом ARPPU при падающей конверсии (опасно — вы выжимаете ядро и теряете периферию).
2.5. Referral — рекомендации
k-фактор = (число приглашений на пользователя) × (конверсия приглашения в регистрацию).
При k ≥ 1 рост самоподдерживающийся — на практике это крайне редко и недолго.
Вторая, менее известная и более важная метрика — viral cycle time: сколько времени
проходит от регистрации до приглашения. При одинаковом k продукт с циклом 2 дня
растёт радикально быстрее, чем с циклом 20 дней.
2.6. Ограничения AARRR
Фреймворк линеен, а реальные продукты — нет. У маркетплейса две воронки (спрос и предложение), они связаны сетевым эффектом; у B2B-SaaS решение о покупке принимает не тот, кто пользуется; у контентного продукта Referral работает раньше Revenue. AARRR — хороший чеклист полноты («мы вообще смотрим на удержание?»), но плохая модель роста. Модель роста строится деревом метрик — раздел 4.
3. North Star: одна метрика, которая держит фокус
3.1. Зачем нужна
Организация из 200 человек не может оптимизировать 40 метрик одновременно — команды начнут тянуть в противоположные стороны (маркетинг растит регистрации, продукт растит конверсию, поддержка растит удовлетворённость, а выручка стоит). North Star Metric (NSM) — единственное число, выражающее ценность, которую продукт даёт пользователям, и через которое компания собирается зарабатывать.
Критерии из Amplitude North Star Playbook:
- выражает ценность для пользователя, а не удобство для компании;
- отражает стратегию (см. https://courses.digitable.life/post/product-management/04-strategy-and-roadmap/), а не текущий спринт;
- является опережающим индикатором выручки;
- управляема продуктовыми решениями;
- понятна любому сотруднику без обучения;
- не vanity — может упасть.
Примеры, ставшие каноном: Airbnb — забронированные ночи; Spotify — время прослушивания; WhatsApp — отправленные сообщения; Amplitude — weekly querying users. Обратите внимание: почти все NSM — это произведение охвата на интенсивность, а не просто «число пользователей».
3.2. Как её собирают правильно
Хорошая NSM почти всегда имеет форму:
NSM = (число пользователей, совершивших ключевое действие за период)
× (интенсивность действия)
× (качество действия)
Например, для сервиса доставки: еженедельные заказчики × заказов на заказчика × доля заказов без инцидента.
Третий множитель — встроенный guardrail: нельзя вырастить NSM, разогнав заказы ценой качества.
3.3. Ограничения и честная критика
NSM — не панацея. Три реальные проблемы:
- Инерция. NSM меняется медленно, отдельная команда за квартал сдвинет её на шум. Поэтому команды работают не с NSM, а с её драйверами (раздел 4).
- Гудхарт в масштабе. Единственная метрика, привязанная к бонусам всей компании, — идеальный объект для оптимизации не по назначению.
- Смена стадии. NSM ранней стадии (активация) не годится для стадии монетизации. Пересматривать её раз в год — нормально; менять каждый квартал — признак отсутствия стратегии.
4. Дерево метрик: как связать фичу с деньгами
Дерево метрик (metric tree, growth model) — декомпозиция NSM на множители, каждый из которых кому-то принадлежит. Это главный рабочий артефакт продакта: он превращает абстрактный «рост» в конечный список рычагов и делает возможной приоритизацию (см. https://courses.digitable.life/post/product-management/03-prioritization/).
еженедельные
завершённые заказы)) Новые пользователи Трафик по каналам Стоимость клика Конверсия лендинга Активация W1 Время до первого заказа Доля дошедших до оплаты Возвращающиеся пользователи Retention W4 Качество первого заказа Скорость доставки Частота заказов Push и email Подписка и бонусы Реактивированные Доля спящих Конверсия реактивации Качество заказа Доля отмен Доля инцидентов Средняя оценка
4.1. Мультипликативная модель и её главный урок
Простейшая модель выручки:
Revenue = Visitors × CR_signup × CR_activation × CR_paid × ARPPU × Lifetime
Посчитаем чувствительность в коде.
from dataclasses import dataclass, replace
@dataclass(frozen=True)
class Funnel:
visitors: int = 200_000 # визитов в месяц
cr_signup: float = 0.08 # визит -> регистрация
cr_activation: float = 0.45 # регистрация -> активация
cr_paid: float = 0.06 # активация -> первая оплата
arppu: float = 900.0 # средний чек платящего, ₽/мес
lifetime_m: float = 7.0 # месяцев жизни платящего
def revenue(self) -> float:
return (self.visitors * self.cr_signup * self.cr_activation
* self.cr_paid * self.arppu * self.lifetime_m)
def sensitivity(base: Funnel, lift: float = 0.10) -> dict[str, float]:
"""Прирост выручки при относительном улучшении каждого драйвера на lift."""
out = {}
r0 = base.revenue()
for field in ("visitors", "cr_signup", "cr_activation", "cr_paid", "arppu", "lifetime_m"):
bumped = replace(base, **{field: getattr(base, field) * (1 + lift)})
out[field] = bumped.revenue() / r0 - 1
return out
base = Funnel()
print(f"Выручка: {base.revenue():,.0f} ₽/мес")
for name, delta in sensitivity(base).items():
print(f"{name:>15}: +{delta:.1%}")
Вывод одинаков для всех драйверов: +10%. Это не баг модели, а её содержательный
результат: в чисто мультипликативной воронке важен не сам множитель, а достижимый
относительный прирост на единицу усилий. Поднять cr_paid с 6% до 6.6% —
работа на квартал; поднять visitors на 10% — вопрос бюджета. Поэтому дерево метрик
не заменяет приоритизацию, а даёт ей единицу измерения: «сколько процентов выручки
стоит этот рычаг».
Асимметрия появляется там, где связь нелинейна. Классический пример — retention,
который входит в LTV через 1/churn:
def ltv_simple(arppu: float, gross_margin: float, monthly_churn: float) -> float:
"""Геометрическая модель: LTV = маржинальная выручка / отток."""
return arppu * gross_margin / monthly_churn
base_ltv = ltv_simple(900, 0.80, 0.12) # отток 12%/мес -> 6000 ₽
better = ltv_simple(900, 0.80, 0.12 * 0.90) # отток -10% относительно -> 6667 ₽
print(f"{base_ltv:.0f} -> {better:.0f}, прирост {better/base_ltv - 1:.1%}") # +11.1%
При оттоке 12% улучшение на 10% даёт +11.1% LTV; при оттоке 3% то же относительное улучшение даёт те же +11.1%, но в абсолютных рублях — в четыре раза больше. Retention — единственная метрика воронки с таким рычагом, поэтому она почти всегда недоинвестирована относительно её экономической ценности.
Сложность вычислений здесь тривиальна: дерево из n узлов считается за O(n),
чувствительность методом «сдвинь один драйвер» — за O(n) пересчётов дерева, то есть O(n²)
в худшем случае для глубоких деревьев. Для реальных деревьев (30–80 узлов) это доли секунды,
поэтому пересчёт можно делать интерактивно прямо в BI.
5. Retention: как считать и как читать
5.1. Три несовместимых определения
Прежде чем спорить о числе, договоритесь об определении. Их три, и они дают принципиально разные значения на одних данных (Mixpanel: Retention Report):
| Тип | Определение | Когда применять |
|---|---|---|
| N-day (bounded) | вернулся ровно на день N | продукты с ежедневным ритмом: игры, соцсети |
| Unbounded (rolling) | вернулся в день N или позже | редкие сценарии: билеты, страховки, крупные покупки |
| Bracket (range) | вернулся в интервале [N, M] | SaaS и всё, что живёт неделями и месяцами |
N-day для B2B-инструмента даст 4% и панику, bracket-недельный на тех же данных — 60% и спокойствие. Обе цифры «правильные». Всегда пишите определение рядом с числом.
5.2. Форма кривой важнее её уровня
Единственный вопрос к кривой удержания: выходит ли она на плато. Плато означает, что существует ядро пользователей, для которых продукт стал привычкой — этих людей можно масштабировать привлечением. Кривая, уходящая в ноль, означает, что каждый вложенный в маркетинг рубль сгорает, и никакой объём привлечения бизнес не спасёт.
Обратите внимание на левую часть картинки: в первую неделю обе кривые почти совпадают. Решение о жизнеспособности продукта, принятое по D1/D7, регулярно оказывается ошибочным в обе стороны. Минимальный горизонт — 8 недель, для B2B — 3–6 месяцев.
Ориентиры «что такое хорошо» сильно зависят от категории; разборы бенчмарков с реальными данными публикует Ленни Рачицкий (What is good retention?).
5.3. Жизненный цикл пользователя как автомат
Считать «активных» вообще — бессмысленно. Полезно разложить базу на состояния и смотреть на потоки между ними: именно потоки — управляемая величина.
в первые 7 дней New --> Churned: не активировался за 14 дней Activated --> Retained: вернулся
в следующем периоде Retained --> Retained: продолжает пользоваться Retained --> Dormant: нет активности 28 дней Activated --> Dormant: разовое использование Dormant --> Resurrected: вернулся сам
или после кампании Resurrected --> Retained: закрепился Dormant --> Churned: нет активности 90 дней Churned --> [*] note right of Dormant Dormant — не потерянные. Стоимость реактивации обычно в 3-5 раз ниже CAC. end note
Из этого автомата получается уравнение роста базы:
MAU(t) = MAU(t-1) + New(t) + Resurrected(t) − Churned(t)
Отношение (New + Resurrected) / Churned — это Quick Ratio (термин из портфельной
аналитики Social Capital). При значении < 1 база сокращается, сколько бы вы ни привлекали.
Это самая честная одноцифровая диагностика здоровья продукта.
5.4. Код: когортный retention на pandas
import pandas as pd
import numpy as np
# users: user_id, signup_date (datetime64)
# events: user_id, event_date (datetime64) — любое «активное» действие
def weekly_retention(users: pd.DataFrame,
events: pd.DataFrame,
today: pd.Timestamp) -> pd.DataFrame:
"""Матрица удержания: строки — недельные когорты, столбцы — номер недели жизни."""
df = events.merge(users, on="user_id", how="inner")
# Номер недели жизни пользователя относительно его собственной регистрации.
df["week_index"] = (df["event_date"] - df["signup_date"]).dt.days // 7
df = df[df["week_index"] >= 0] # защита от событий до регистрации
df["cohort"] = df["signup_date"].dt.to_period("W")
active = (df.groupby(["cohort", "week_index"])["user_id"]
.nunique()
.unstack(fill_value=0))
size = users.groupby(users["signup_date"].dt.to_period("W"))["user_id"].nunique()
retention = active.div(size, axis=0)
# КРИТИЧНО: маскируем правое цензурирование. Молодая когорта физически
# не могла дожить до недели N — без маски она занизит средние по столбцу.
weeks_lived = ((today - retention.index.to_timestamp()).days // 7)
mask = np.arange(retention.shape[1])[None, :] <= np.asarray(weeks_lived)[:, None]
return retention.where(mask)
# Пример синтетических данных
rng = np.random.default_rng(42)
n = 5_000
users = pd.DataFrame({
"user_id": range(n),
"signup_date": pd.Timestamp("2026-01-05") + pd.to_timedelta(rng.integers(0, 120, n), "D"),
})
rows = []
for uid, signup in zip(users.user_id, users.signup_date):
alive_weeks = rng.geometric(p=0.25) # у части пользователей короткая жизнь
if rng.random() < 0.30: # ядро с привычкой
alive_weeks += rng.integers(8, 30)
for w in range(alive_weeks):
rows.append((uid, signup + pd.Timedelta(weeks=int(w), days=int(rng.integers(0, 7)))))
events = pd.DataFrame(rows, columns=["user_id", "event_date"])
ret = weekly_retention(users, events, today=pd.Timestamp("2026-06-01"))
print((ret.iloc[:, :9] * 100).round(1))
Сложность: группировка O(E) по числу событий плюс O(C·W) на построение матрицы,
где C — когорт, W — недель. Память — O(C·W), то есть матрица всегда крошечная;
узкое место — исходная таблица событий, поэтому в проде агрегация делается на стороне
хранилища (см. SQL ниже), а в pandas приезжает уже свёрнутый результат.
5.5. Тот же расчёт на SQL
-- Недельный bracket-retention. Работает в BigQuery / ClickHouse / Postgres
-- с минимальными правками синтаксиса date_trunc.
WITH cohorts AS (
SELECT user_id,
date_trunc('week', signup_at) AS cohort_week
FROM users
),
activity AS (
SELECT c.user_id,
c.cohort_week,
CAST(FLOOR(DATE_DIFF(e.event_at, c.cohort_week, DAY) / 7) AS INT64) AS week_index
FROM events e
JOIN cohorts c USING (user_id)
WHERE e.event_name IN ('order_completed', 'report_created') -- «ключевое действие»
AND e.event_at >= c.cohort_week
),
sized AS (
SELECT cohort_week, COUNT(*) AS cohort_size
FROM cohorts GROUP BY cohort_week
)
SELECT a.cohort_week,
a.week_index,
COUNT(DISTINCT a.user_id) AS retained,
s.cohort_size,
ROUND(COUNT(DISTINCT a.user_id) / s.cohort_size, 4) AS retention
FROM activity a
JOIN sized s USING (cohort_week)
-- отсекаем незрелые точки: когорта должна прожить week_index полных недель
WHERE DATE_ADD(a.cohort_week, INTERVAL (a.week_index + 1) WEEK) <= CURRENT_DATE()
GROUP BY a.cohort_week, a.week_index, s.cohort_size
ORDER BY a.cohort_week, a.week_index;
Обратите внимание на предпоследнюю строку — это то самое отсечение правого цензурирования. Его забывают чаще всего, и в результате последние когорты выглядят «ухудшающимися», хотя они просто моложе.
6. Unit-экономика: сходится ли бизнес
6.1. Идея
Unit-экономика отвечает на вопрос: зарабатываем ли мы на одном клиенте больше, чем тратим на его привлечение и обслуживание? Если нет, рост увеличивает убыток — масштабируется не бизнес, а дыра.
Единица («юнит») выбирается по природе продукта: клиент — для SaaS, заказ — для маркетплейса, автомобиль в городе — для каршеринга. Ошибка выбора юнита обесценивает весь расчёт: считать экономику маркетплейса на клиента, а не на заказ, значит спрятать в среднем переменные затраты, которые растут с каждой транзакцией.
6.2. Формулы
Contribution margin (CM) на юнит = Выручка − Переменные затраты
переменные: эквайринг, налог с оборота, хостинг/трафик на пользователя,
стоимость поддержки, бонусы и промокоды, доставка
LTV (по когорте, дискретно) = Σ_{t=0..T} CM_t · S_t / (1 + d)^t
S_t — доля когорты, дожившая до периода t; d — ставка дисконтирования
LTV (геометрическое приближение) = CM_месяц / churn_месяц
CAC = (маркетинг + продажи + скидки на привлечение) / число новых клиентов
Payback = число месяцев, за которое кумулятивный CM покрывает CAC
Два практических ориентира из SaaS Metrics 2.0 Дэвида Скока:
LTV / CAC ≥ 3 и payback ≤ 12 месяцев. Это не законы природы, а эвристики: LTV/CAC = 3
примерно соответствует состоянию, где после переменных затрат и привлечения остаётся
достаточно на R&D, админку и прибыль. LTV/CAC = 10 — не победа, а сигнал, что вы
недоинвестируете в рост и оставляете рынок конкурентам.
6.3. Главная ошибка — «геометрический» LTV на реальных данных
Формула LTV = ARPU/churn предполагает постоянный отток. Реальные кривые удержания
имеют падающий hazard rate: кто выжил полгода, уходит гораздо реже новичка. Средний
отток по базе поэтому одновременно переоценивает жизнь новичков и недооценивает жизнь ядра.
Правильный путь — считать LTV по когортам, из фактической кривой, а хвост экстраполировать явной моделью с честно указанной неопределённостью.
import numpy as np
from scipy.optimize import curve_fit
def survival(t, plateau, decay):
"""Модель «затухание + плато»: S(t) = c + (1-c)·exp(-t/tau)."""
return plateau + (1.0 - plateau) * np.exp(-t / decay)
# факт: доля когорты, активная в месяце t (t=0 — месяц регистрации)
t_obs = np.arange(0, 9)
s_obs = np.array([1.00, 0.62, 0.48, 0.41, 0.38, 0.36, 0.352, 0.348, 0.345])
(plateau, decay), cov = curve_fit(survival, t_obs, s_obs, p0=[0.3, 2.0],
bounds=([0.0, 0.1], [0.9, 60.0]))
print(f"плато = {plateau:.3f}, tau = {decay:.2f} мес, "
f"σ(плато) = {np.sqrt(cov[0, 0]):.3f}")
def ltv(cm_per_month: float, horizon: int, d_annual: float = 0.20) -> float:
"""Дисконтированный LTV на горизонте horizon месяцев."""
d_m = (1 + d_annual) ** (1 / 12) - 1
t = np.arange(horizon)
return float(np.sum(cm_per_month * survival(t, plateau, decay) / (1 + d_m) ** t))
CM = 820.0 # маржинальная выручка на активного клиента в месяц
CAC = 600.0 * 5 # CAC когорты в расчёте на одного платящего
for h in (12, 24, 36):
v = ltv(CM, h)
print(f"горизонт {h:>2} мес: LTV = {v:,.0f} ₽, LTV/CAC = {v / CAC:.2f}")
# Payback: первый месяц, где кумулятивный дисконтированный CM покрывает CAC
d_m = (1 + 0.20) ** (1 / 12) - 1
cum = np.cumsum(CM * survival(np.arange(60), plateau, decay) / (1 + d_m) ** np.arange(60))
idx = np.argmax(cum >= CAC)
print(f"payback ≈ {idx + 1} мес" if cum[idx] >= CAC else "payback не достигается за 60 мес")
Три дисциплины, которые отличают взрослый расчёт от студенческого:
- Горизонт указывается явно. «LTV = 24 000 ₽» без горизонта — бессмысленное число. Стандарт индустрии — 12 или 24 месяца; бесконечный горизонт запрещён здравым смыслом (вы не знаете, что будет с продуктом через 5 лет).
- Дисконтирование. Рубль через два года дешевле рубля сегодня, а для стартапа, привлекающего капитал под 20–30%, — существенно дешевле.
- В LTV идёт contribution margin, а не выручка. LTV, посчитанный по валовой выручке, завышен ровно на долю переменных затрат — то есть в e-commerce вдвое-втрое.
6.4. Как это выглядит в отчёте когорты
Правильная таблица юнит-экономики — не одна строка, а когорты по месяцу привлечения:
| Когорта | Клиентов | CAC | CM накопл. M3 | CM накопл. M12 | Payback | LTV/CAC (24 мес) |
|---|---|---|---|---|---|---|
| 2025-09 | 1 240 | 2 800 ₽ | 1 900 ₽ | 4 400 ₽ | 8 мес | 3.1 |
| 2025-12 | 2 610 | 3 900 ₽ | 1 700 ₽ | — | прогноз 13 мес | прогноз 2.2 |
| 2026-03 | 4 050 | 5 100 ₽ | 1 500 ₽ | — | прогноз 19 мес | прогноз 1.5 |
Это самая частая история масштабирования: CAC растёт быстрее качества трафика (вычерпаны дешёвые каналы), CM когорты падает, экономика разъезжается — но по агрегату «средний LTV/CAC по компании» это видно только через год. Когортный разрез показывает разворот за квартал.
7. Модель данных: без чего метрики не существуют
Метрики — производная от событийной модели. Если события пишутся как попало, любой дашборд врёт, и это не лечится SQL-запросом.
Четыре детали, которые ломают метрики чаще всего:
occurred_atпротивreceived_at. Мобильный клиент офлайн отправит события через сутки. Если считать по времени приёма, вчерашний DAU «дорастёт» задним числом, и все ежедневные отчёты станут нестабильными. Считайте поoccurred_at, но окно закрывайте с лагом (например, T+2).- Идемпотентность. Ретраи клиента — норма. Без
event_idи дедупликации метрики завышены на единицы процентов, и никто этого не заметит. - Словарь событий (tracking plan) с владельцем и версией. Событие
checkout_done, у которого разработчик поменял смысл поляamountс «до скидки» на «после», создаёт разрыв во всех исторических рядах. - Единый идентификатор до и после логина. Иначе воронка «аноним → регистрация» не сшивается, и конверсия считается по фантомам.
Инженерная часть этого — предмет трека data engineering; продуктовая — в https://courses.digitable.life/post/product-management/08-analytics-and-decisions/.
8. Guardrails, OEC и как не сломать продукт ростом метрики
OEC (Overall Evaluation Criterion) — термин Ронни Кохави: заранее зафиксированная формула, по которой принимается решение об успехе изменения, включающая и целевую метрику, и ограничения. Это защита от Гудхарта на уровне процесса.
Практическая конструкция для любого запуска:
| Роль метрики | Пример | Правило |
|---|---|---|
| Target | конверсия в оплату | должна вырасти статистически значимо |
| Guardrail | p95 времени загрузки, доля отписок, crash-free rate, тикеты в поддержку | не должна ухудшиться более чем на порог |
| Counter-metric | средний чек при росте конверсии, retention при росте DAU | явно проверяем, что рост не за счёт неё |
| Health/data quality | доля событий без user_id, SRM (перекос долей групп) | нарушение = эксперимент недействителен |
Пример боевого правила: «раскатываем, если конверсия +≥1.5% при p<0.05, и при этом p95 latency не выросла более чем на 50 мс, а недельный retention не упал более чем на 0.5 п.п.». Порог фиксируется до запуска, иначе он станет предметом переговоров после.
Подробности статистики — в https://courses.digitable.life/post/product-management/05-mvp-and-experiments/; книга-эталон — Kohavi, Tang, Xu, «Trustworthy Online Controlled Experiments».
9. Типичные ошибки, которые дорого стоят
1. Средние по скошенным распределениям. ARPU, время сессии, число заказов — распределения с длинным хвостом. Среднее двигают «киты». Смотрите медиану и перцентили (p50/p90/p99) и гистограмму; если среднее и медиана расходятся втрое, среднее не описывает никого.
2. Парадокс Симпсона. Метрика растёт в каждом сегменте и падает в целом (или наоборот), потому что изменились доли сегментов. Конкретно:
| Сегмент | Было | Стало |
|---|---|---|
| Desktop | 300/1000 = 30% | 165/500 = 33% |
| Mobile | 100/1000 = 10% | 175/1500 = 11.7% |
| Итого | 400/2000 = 20% | 340/2000 = 17% |
Конверсия выросла на обеих платформах, но общая упала: закупили дешёвый мобильный трафик, и доли сегментов изменились. Правило: любое изменение агрегата проверяйте разбивкой по основным измерениям (платформа, канал, страна, новизна пользователя).
3. Ошибка выжившего в когортах. Смотреть на поведение только активных пользователей и делать вывод «те, кто пользуются фичей X, дольше живут». Проверяется только экспериментом или как минимум сравнением с matched-контролем.
4. Незрелые когорты в среднем. Разобрано в 5.4/5.5 — маскируйте правое цензурирование.
5. Смена определения метрики без версии. «Активный пользователь» тихо переопределили с «открыл приложение» на «совершил действие», ряд сломался, полгода все спорят о причинах падения. Определения метрик — код: в git, с владельцем, с датой изменения и с обязательным пересчётом истории.
6. Novelty effect и сезонность. Новая фича даёт всплеск от любопытства и затухает за 2–3 недели. Одна неделя измерения — не измерение. Годовые сезонные эффекты (декабрь, каникулы) сравнивайте год к году, а не месяц к месяцу.
7. Метрика без владельца. Число, за которое не отвечает конкретный человек, не двигается. Каждый узел дерева метрик должен иметь имя рядом.
8. Слишком много метрик. Дашборд с 60 графиками не читает никто. Рабочий формат: 1 NSM + 5–7 драйверов + guardrails. Остальное — по запросу, в разрезах.
10. Как это устроено на практике
Как выглядит зрелая система метрик в компании — по нарастанию:
- Определения в коде. Метрики описаны в семантическом слое (dbt metrics, LookML, Cube) один раз, а не переписываются в каждом дашборде. Это устраняет ситуацию, когда у маркетинга и продукта разный «активный пользователь».
- Tracking plan как контракт. Схема событий валидируется в CI, событие без владельца и описания в прод не попадает.
- Weekly business review. Регулярная встреча, где смотрят дерево метрик сверху вниз, а не «что мы выкатили». Формат: что изменилось, почему, что делаем.
- Дефолтный набор к каждому запуску. Target + guardrails фиксируются в документе фичи до разработки. Через 2–4 недели после релиза — обязательный пост-анализ, и это единственный способ не стать фабрикой фич (см. https://courses.digitable.life/post/product-management/00-overview/).
- Экономика в разрезе когорт — часть операционного цикла, а не разовое упражнение перед раундом инвестиций.
Полезная привычка: раз в квартал брать каждую метрику на главном дашборде и задавать единственный вопрос — «какое решение мы приняли из-за неё за последние три месяца?». Метрики без ответа удаляются. Дашборд, который не худеет, всегда растёт до нечитаемости.
Мини-итог
- Метрика — сжатие реальности ради сравнения; объясняют изменения когорты и сегменты, а не число.
- Хорошая метрика сравнительна, понятна, является отношением и меняет поведение. Накопительные счётчики — vanity.
- AARRR — чеклист полноты покрытия жизненного цикла, а не модель роста.
- North Star даёт фокус; работают команды с её драйверами через дерево метрик, которое переводит фичи в проценты выручки.
- Retention важнее уровня — важна форма кривой: есть плато или нет. Всегда указывайте тип определения (N-day / unbounded / bracket) и маскируйте незрелые когорты.
- Unit-экономика считается на contribution margin, по когортам, с явным горизонтом
и дисконтированием.
LTV/CAC ≥ 3иpayback ≤ 12 мес— эвристики, а не законы. - Любая целевая метрика требует guardrails, зафиксированных до запуска, иначе закон Гудхарта сработает обязательно.
Источники
- Dave McClure, Startup Metrics for Pirates (AARRR)
- Alistair Croll, Benjamin Yoskovitz, «Lean Analytics», O’Reilly
- Amplitude, The North Star Playbook
- Ron Kohavi, Diane Tang, Ya Xu, «Trustworthy Online Controlled Experiments»
- David Skok, SaaS Metrics 2.0
- Andreessen Horowitz, 16 Startup Metrics
- Andrew Chen, The Law of Shitty Clickthroughs
- Lenny Rachitsky, What is good retention?
- Mixpanel Docs, Retention Report
- Melissa Perri, «Escaping the Build Trap», O’Reilly
Что дальше
Метрики говорят, где болит, но не говорят, что делать первым. Следующий шаг — превратить дерево метрик и поток идей в упорядоченную очередь работ: Приоритизация: RICE, ICE, Kano, MoSCoW, WSJF.