К списку метрик
ENGAGEMENT

Net Promoter Score (NPS)

Net Promoter Score

Доля promoters минус доля detractors по вопросу «порекомендуете нам?».

ФОРМУЛА

$$\text{NPS} = %,Promoters - %,Detractors$$ где Promoters — оценка 9-10, Detractors — 0-6 по шкале 0-10.

ОПИСАНИЕ

Что измеряет: lojal'nost' пользователей и word-of-mouth потенциал.

Шкала: 0-10. Группировка:

  • 0-6: Detractors (недовольны)
  • 7-8: Passives (нейтральны, в расчёт не входят)
  • 9-10: Promoters (рекомендуют активно)

NPS = % Promoters - % Detractors. Диапазон от -100 до +100.

Бенчмарки (Bain & Co):

ИндустрияAverage NPSTop 10%
Banking (Каспи лидер)30-5070+
Telecom (KCell, Beeline)0-2040+
Insurance20-4060+
Tech consumer (Apple)60+80+
Airlines (Air Astana)10-3050+

Каспи имеет NPS ~75 — один из highest в банкинге Казахстана.

Когда полезен и когда нет:

Полезен:

  • Trend over time (NPS вырос с 30 до 50 → win)
  • Сегментный анализ (NPS premium vs free)
  • Корреляция с retention/revenue (validation что NPS predictiven)

Не полезен:

  • Сравнение между индустриями (разные benchmarks)
  • Малое количество respondents (<100) — большой шум
  • Self-reported, не наблюдаемое поведение

Pitfalls:

  1. Selection bias: на опрос отвечают чаще довольные ИЛИ очень недовольные. Result — bimodal, не отражает «среднего» юзера.

  2. Goodhart's law: если KPI команды — NPS, они оптимизируют под опрос, не реальное удовлетворение. Видел сценарии где компания просит «9-10 ответы плиз» — это деградация метрики.

  3. NPS не predictive в B2B: часто решение остаться/уйти принимает не respondent (junior), а его boss. NPS низкий, но клиент остаётся.

SQL ПРИМЕР
-- Месячный NPS
SELECT
  date_trunc('month', survey_date) AS month,
  COUNT(*) AS responses,
  ROUND(100.0 * COUNT(*) FILTER (WHERE score >= 9) / COUNT(*), 1) AS promoters_pct,
  ROUND(100.0 * COUNT(*) FILTER (WHERE score <= 6) / COUNT(*), 1) AS detractors_pct,
  ROUND(100.0 * COUNT(*) FILTER (WHERE score >= 9) / COUNT(*) -
        100.0 * COUNT(*) FILTER (WHERE score <= 6) / COUNT(*), 1) AS nps
FROM nps_surveys
WHERE survey_date >= '2026-01-01'
GROUP BY 1
ORDER BY 1;
PYTHON ПРИМЕР
def nps(scores: pd.Series) -> float:
    promoters = (scores >= 9).mean() * 100
    detractors = (scores <= 6).mean() * 100
    return promoters - detractors

monthly_nps = (surveys
    .assign(month=surveys["survey_date"].dt.to_period("M"))
    .groupby("month")["score"]
    .apply(nps))