Как посчитать payback по когортам в SQL

Закрепи формулу payback by cohort в Карьернике
Запомнить надолго — 5 коротких сессий с задачами на эту тему. Бесплатно
Тренировать payback by cohort в Telegram

Зачем payback по cohort

Average payback не покажет, что Google Ads-cohort окупается за 4 месяца, а Facebook — за 10. Cohort-based payback — единственный способ принять решение «куда вливать бюджет»: ускорить эффективные каналы, прибить медленные.

Идея

payback_month = min k such that cumulative_revenue_per_user(k) >= CAC

Кумулятив прирастает каждый месяц, на какой-то точке догоняет CAC — это payback.

Payback в SQL

WITH cohort_ltv AS (
    SELECT cohort_month, months_since, cumulative_ltv FROM ltv_table
),
cac_per_cohort AS (
    SELECT cohort_month, AVG(cac) AS cac FROM cohort_acquisition_cost GROUP BY cohort_month
),
joined AS (
    SELECT
        l.cohort_month,
        l.months_since,
        l.cumulative_ltv,
        c.cac,
        l.cumulative_ltv >= c.cac AS paid_back
    FROM cohort_ltv l
    JOIN cac_per_cohort c USING (cohort_month)
)
SELECT
    cohort_month,
    cac,
    MIN(months_since) FILTER (WHERE paid_back) AS payback_months
FROM joined
GROUP BY cohort_month, cac
ORDER BY cohort_month;

Если payback_months IS NULL для cohort — она ещё не окупилась (или вообще никогда).

По каналу

WITH joined AS (
    SELECT
        utm_source,
        cohort_month,
        months_since,
        cumulative_ltv >= cac AS paid_back
    FROM ltv_with_cac
),
per_cohort AS (
    SELECT
        utm_source,
        cohort_month,
        MIN(months_since) FILTER (WHERE paid_back) AS payback_months
    FROM joined
    GROUP BY utm_source, cohort_month
)
SELECT
    utm_source,
    AVG(payback_months) AS avg_payback_months
FROM per_cohort
WHERE payback_months IS NOT NULL
GROUP BY utm_source
ORDER BY avg_payback_months;

Канал с самым коротким payback — приоритет для масштабирования.

Закрепи формулу payback by cohort в Карьернике
Запомнить надолго — 5 коротких сессий с задачами на эту тему. Бесплатно
Тренировать payback by cohort в Telegram

Маржинальный payback

Если есть gross margin, payback считается на margin, не на revenue:

WITH joined AS (
    SELECT
        cohort_month,
        months_since,
        cumulative_ltv * gross_margin_pct / 100.0 AS cumulative_margin,
        cac
    FROM ltv_with_cac
)
SELECT
    cohort_month,
    MIN(months_since) FILTER (WHERE cumulative_margin >= cac) AS payback_on_margin
FROM joined
GROUP BY cohort_month
ORDER BY cohort_month;

Это честнее: компания зарабатывает margin, не revenue.

Частые ошибки

Ошибка 1. CAC всем cohort одинаковый. В реальности CAC меняется по месяцам (cost per click растёт). Считайте per-cohort CAC.

Ошибка 2. Считать payback на revenue без margin. Revenue, не margin, — переоценивает скорость окупаемости.

Ошибка 3. Игнорировать churn. Если в cohort 50% churned до payback, на оставшихся 50% revenue растёт быстрее — но cohort overall payback дольше.

Ошибка 4. Маленькие cohort. < 50 customers — payback шумит. Aggregate несколько месяцев.

Ошибка 5. Включать new customers в cumulative. Cumulative — на ЗАКРЕПЛЁННЫЕ customers cohort. New, пришедшие в month k, считаются в свою cohort.

Связанные темы

FAQ

Payback или LTV?

Payback — speed of recovery. LTV — total return. Smart growth-team смотрит оба.

Какой payback хороший?

SaaS B2C: 3-12 месяцев. B2B: 12-24. Enterprise: 24+.

Cohort с CR < 100% — что значит?

Cohort убыточная: revenue никогда не покрывает CAC. Канал надо переосмыслить.

CAC по cohort = CAC канала?

Не всегда. CAC канала за всё время. CAC cohort — только за период этого месяца.

Payback меньше 1 — возможно?

Да, если cohort впервые платит upfront annual. Часто бывает в Enterprise.