# Magic Number: как найти действие, которое удерживает пользователей

> Методология поиска magic number продукта: когортный анализ в SQL, AI-корреляция пользовательских действий с 30-day retention, валидация через A/B тесты. Готовые запросы и промпты.
> Author: Roman Belov · Published: 2026-04-09 · Source: https://futurecraft.pro/ru/blog/magic-number-retention/

У Facebook в 2009 году аналитики нашли закономерность: пользователи, добавившие 7 друзей за первые 10 дней, оставались в продукте значительно чаще остальных. У Slack порог оказался другим: 2000 сообщений в команде. У Dropbox — одно расшаренное действие с файлом. Каждый из этих продуктов нашёл свой magic number: пороговое количество действий, после которого вероятность удержания резко возрастает.

Статья о том, как найти magic number собственного продукта: от сырых событий в базе до конкретного числа, подтверждённого данными. С SQL-запросами для когортного анализа, промптами для AI-корреляции и методологией валидации.

## Что такое magic number

Magic number — это конкретное действие, совершённое конкретное число раз в конкретный период, после которого retention пользователя скачкообразно растёт. Не абстрактная метрика вовлечённости, а точная формула: "пользователь, который сделал X минимум N раз за первые D дней, остаётся с вероятностью Y%".

Примеры из реальных продуктов:

- **Facebook:** 7 друзей за 10 дней. Пользователи, достигшие порога, удерживались значительно лучше остальных — точный множитель компания не публиковала.
- **Slack:** 2000 сообщений в команде. После этого порога 93% команд продолжали платить за продукт.
- **Twitter (X):** подписка на 30 аккаунтов — порог, вокруг которого growth-команда строила онбординг.
- **Dropbox:** 1 файл в shared folder. Одно коллаборативное действие считалось сильнейшим ранним сигналом будущей конверсии в платный план.

Magic number работает на двух уровнях. На уровне продукта он показывает, куда направить ресурсы: онбординг, UX, маркетинг. На уровне [unit-экономики](/ru/blog/unit-economics-calculator-ai/) он напрямую влияет на LTV, так как каждый процент прироста retention снижает стоимость привлечения.

## Подготовка данных

Перед поиском корреляций нужны чистые данные. Минимальный набор: таблица событий с user_id, event_name, timestamp и таблица пользователей с датой регистрации.

### Структура таблиц

```sql
-- Таблица событий (events)
-- user_id | event_name | event_timestamp | properties (jsonb)

-- Таблица пользователей (users)
-- user_id | created_at | acquisition_source | plan
```

### Определение retention

Для magic number анализа используется N-day retention: вернулся ли пользователь на день N после регистрации. Стандартный выбор — 30-day retention. Для продуктов с коротким циклом (мессенджеры, игры) подойдёт 7-day. Для B2B SaaS с длинным онбордингом — 60 или 90 дней.

```sql
-- Базовая таблица retention: вернулся ли пользователь на 30-й день
WITH user_retention AS (
  SELECT
    u.user_id,
    u.created_at,
    CASE
      WHEN EXISTS (
        SELECT 1 FROM events e
        WHERE e.user_id = u.user_id
          AND e.event_timestamp::date
              BETWEEN u.created_at::date + INTERVAL '27 days'
                  AND u.created_at::date + INTERVAL '33 days'
      ) THEN 1
      ELSE 0
    END AS retained_day30
  FROM users u
  WHERE u.created_at < NOW() - INTERVAL '33 days'
)
SELECT
  COUNT(*) AS total_users,
  SUM(retained_day30) AS retained_users,
  ROUND(100.0 * SUM(retained_day30) / COUNT(*), 2) AS retention_rate
FROM user_retention;
```

Окно ±3 дня (27–33) вместо точного 30-го дня сглаживает шум. Пользователь, вернувшийся на 29-й или 31-й день, по поведению не отличается от вернувшегося ровно на 30-й.

## Когортный анализ действий в SQL

Задача: посчитать для каждого типа действия, сколько раз его совершил каждый пользователь в первые N дней, и сопоставить с retention.

### Подсчёт действий в активационном окне

```sql
-- Количество каждого действия на пользователя за первые 14 дней
WITH activation_actions AS (
  SELECT
    e.user_id,
    e.event_name,
    COUNT(*) AS action_count
  FROM events e
  JOIN users u ON e.user_id = u.user_id
  WHERE e.event_timestamp BETWEEN u.created_at
    AND u.created_at + INTERVAL '14 days'
  GROUP BY e.user_id, e.event_name
)
SELECT * FROM activation_actions;
```

Почему 14 дней? Это стандартное активационное окно. Слишком короткое (1–3 дня) отсечёт пользователей с медленным онбордингом. Слишком длинное (30+ дней) смешает причину и следствие: пользователь не потому остался, что сделал действие на 25-й день, а потому что уже решил остаться.

### Корреляция действий с retention

```sql
-- Retention rate для каждого действия и порогового количества
WITH user_retention AS (
  SELECT
    u.user_id,
    u.created_at,
    CASE
      WHEN EXISTS (
        SELECT 1 FROM events e
        WHERE e.user_id = u.user_id
          AND e.event_timestamp::date
              BETWEEN u.created_at::date + INTERVAL '27 days'
                  AND u.created_at::date + INTERVAL '33 days'
      ) THEN 1
      ELSE 0
    END AS retained_day30
  FROM users u
  WHERE u.created_at < NOW() - INTERVAL '33 days'
),
activation_actions AS (
  SELECT
    e.user_id,
    e.event_name,
    COUNT(*) AS action_count
  FROM events e
  JOIN users u ON e.user_id = u.user_id
  WHERE e.event_timestamp BETWEEN u.created_at
    AND u.created_at + INTERVAL '14 days'
  GROUP BY e.user_id, e.event_name
),
thresholds AS (
  SELECT generate_series(1, 20) AS threshold
),
event_names AS (
  SELECT DISTINCT event_name FROM activation_actions
),
user_flags AS (
  -- Каждая комбинация пользователь × событие × порог с флагом did_action.
  -- Пользователи без события получают did_action = 0 и попадают
  -- в группу «ниже порога», а не в NULL-группу
  SELECT
    ur.user_id,
    ur.retained_day30,
    en.event_name,
    t.threshold,
    CASE WHEN COALESCE(aa.action_count, 0) >= t.threshold
         THEN 1 ELSE 0 END AS did_action
  FROM user_retention ur
  CROSS JOIN event_names en
  CROSS JOIN thresholds t
  LEFT JOIN activation_actions aa
    ON aa.user_id = ur.user_id
   AND aa.event_name = en.event_name
),
stats AS (
  SELECT
    event_name,
    threshold,
    COUNT(*) FILTER (WHERE did_action = 1) AS users_above,
    COUNT(*) FILTER (WHERE did_action = 1 AND retained_day30 = 1)
      AS retained_above,
    ROUND(
      100.0 * COUNT(*) FILTER (WHERE did_action = 1 AND retained_day30 = 1)
      / NULLIF(COUNT(*) FILTER (WHERE did_action = 1), 0),
      2
    ) AS retention_rate_above,
    ROUND(
      100.0 * COUNT(*) FILTER (WHERE did_action = 0 AND retained_day30 = 1)
      / NULLIF(COUNT(*) FILTER (WHERE did_action = 0), 0),
      2
    ) AS retention_rate_below
  FROM user_flags
  GROUP BY event_name, threshold
  HAVING COUNT(*) FILTER (WHERE did_action = 1) >= 30
)
SELECT *
FROM stats
ORDER BY retention_rate_above - retention_rate_below DESC;
```

Этот запрос перебирает пороги от 1 до 20 для каждого типа события. Для каждой пары (событие, порог) считает retention среди пользователей выше и ниже порога. Пользователи, ни разу не совершившие событие, через `COALESCE(action_count, 0)` учитываются в группе «ниже порога», а не теряются в NULL-группе. Результат сортируется по разнице в retention: чем больше разрыв, тем сильнее корреляция.

Фильтр `HAVING >= 30` отсекает пороги с малой выборкой. Retention 100% при двух пользователях ничего не значит.

### Чтение результатов

Пример выходных данных:

| event_name | threshold | users_above | retained_above | retention_above | retention_below |
|---|---|---|---|---|---|
| invite_teammate | 3 | 847 | 612 | 72.25% | 18.40% |
| create_project | 5 | 1203 | 780 | 64.84% | 22.10% |
| share_document | 2 | 1456 | 890 | 61.13% | 20.50% |
| add_integration | 1 | 634 | 365 | 57.57% | 24.30% |

В этом примере invite_teammate >= 3 даёт максимальный разрыв: 72.25% против 18.40%. Разница в 53.85 п.п. Это сильный кандидат на magic number.

## AI-корреляция: промпты для анализа

SQL-запросы дают таблицы. AI помогает интерпретировать результаты, найти неочевидные паттерны и отфильтровать ложные корреляции.

### Промпт 1: анализ корреляционной таблицы

```
Ты product-аналитик. Вот таблица корреляции действий пользователей
с 30-day retention (CSV прилагается).

Задача:
1. Определи ТОП-3 действия с наибольшим разрывом в retention
   между пользователями выше и ниже порога.
2. Для каждого кандидата оцени:
   - Достаточность выборки (users_above > 100)
   - Наличие "перелома" (резкий рост retention на конкретном пороге)
   - Риск обратной каузальности: действие вызывает retention
     или retention вызывает действие?
3. Предложи финального кандидата на magic number с обоснованием.

Формат ответа: таблица кандидатов + вердикт + следующие шаги.
```

### Промпт 2: поиск скрытых паттернов

```
Проанализируй сырые события пользователей (CSV прилагается).
Колонки: user_id, event_name, event_timestamp, retained_day30.

Найди комбинации действий, которые предсказывают retention лучше,
чем одиночные события. Например:
- Пользователь сделал A И B (но не обязательно C)
- Пользователь сделал A в первые 3 дня (а не в первые 14)
- Пользователь сделал A минимум N раз И B минимум M раз

Для каждой найденной комбинации укажи:
- Retention rate для группы "выполнили условие"
- Retention rate для группы "не выполнили"
- Размер выборки обеих групп
- Lift (отношение retention выше/ниже порога)
```

### Промпт 3: валидация кандидата

```
Кандидат на magic number: [действие] >= [порог] за первые [N] дней.

Данные:
- Retention выше порога: X%
- Retention ниже порога: Y%
- Размер выборки: Z пользователей

Проведи критический анализ:
1. Может ли корреляция быть ложной? Какие confounders возможны?
   (источник трафика, платный/бесплатный план, время регистрации)
2. Проверь на survivorship bias: не считаем ли мы только тех,
   кто и так бы остался?
3. Предложи SQL-запрос для контроля confounders
   (стратификация по acquisition source, plan type).
4. Определи минимальный размер A/B теста для подтверждения
   каузальной связи (alpha=0.05, power=0.8).
```

## Поиск magic number по шагам

Полный процесс от идеи до подтверждённого magic number.

### Шаг 1. Инвентаризация событий

Выгрузить все уникальные event_name с количеством пользователей, совершивших каждое:

```sql
SELECT
  event_name,
  COUNT(DISTINCT user_id) AS unique_users,
  COUNT(*) AS total_occurrences,
  ROUND(COUNT(*)::numeric / COUNT(DISTINCT user_id), 1)
    AS avg_per_user
FROM events e
JOIN users u ON e.user_id = u.user_id
WHERE e.event_timestamp BETWEEN u.created_at
  AND u.created_at + INTERVAL '14 days'
GROUP BY event_name
ORDER BY unique_users DESC;
```

Отфильтровать события, которые совершает менее 5% пользователей: их влияние на общий retention будет минимальным даже при сильной корреляции.

### Шаг 2. Корреляционный анализ

Запустить основной запрос из раздела выше. Получить таблицу (event_name, threshold, retention_above, retention_below). Отсортировать по разрыву.

### Шаг 3. Визуализация порогов

Для ТОП-5 кандидатов построить график: ось X — порог (1, 2, 3, ..., 20), ось Y — retention rate. Искать "перелом": точку, после которой retention перестаёт расти или растёт значительно медленнее. Это и есть magic number.

```sql
-- Данные для графика retention vs threshold по конкретному событию
WITH user_ret AS (
  SELECT
    u.user_id,
    CASE
      WHEN EXISTS (
        SELECT 1 FROM events e
        WHERE e.user_id = u.user_id
          AND e.event_timestamp::date
              BETWEEN u.created_at::date + INTERVAL '27 days'
                  AND u.created_at::date + INTERVAL '33 days'
      ) THEN 1
      ELSE 0
    END AS retained
  FROM users u
  WHERE u.created_at < NOW() - INTERVAL '33 days'
),
action_counts AS (
  SELECT
    e.user_id,
    COUNT(*) AS cnt
  FROM events e
  JOIN users u ON e.user_id = u.user_id
  WHERE e.event_name = 'invite_teammate'  -- заменить на нужное
    AND e.event_timestamp BETWEEN u.created_at
      AND u.created_at + INTERVAL '14 days'
  GROUP BY e.user_id
)
SELECT
  t.n AS threshold,
  COUNT(DISTINCT CASE WHEN ac.cnt >= t.n THEN ur.user_id END)
    AS users_above,
  ROUND(
    100.0 * COUNT(DISTINCT CASE WHEN ac.cnt >= t.n
      AND ur.retained = 1 THEN ur.user_id END)
    / NULLIF(COUNT(DISTINCT CASE WHEN ac.cnt >= t.n
      THEN ur.user_id END), 0),
    2
  ) AS retention_pct
FROM user_ret ur
LEFT JOIN action_counts ac ON ur.user_id = ac.user_id
CROSS JOIN generate_series(1, 20) AS t(n)
GROUP BY t.n
ORDER BY t.n;
```

Типичный график перелома: retention растёт с 20% при threshold=1 до 65% при threshold=5, потом выходит на плато (67% при threshold=6, 68% при threshold=7). Magic number = 5.

### Шаг 4. Контроль confounders

Magic number бесполезен, если корреляция объясняется внешним фактором. Три обязательных проверки:

**Источник трафика.** Пользователи из органического поиска часто активнее платных. Если invite_teammate >= 3 работает только для органики, это свойство аудитории, а не magic number продукта.

```sql
-- Стратификация по источнику трафика
SELECT
  u.acquisition_source,
  CASE WHEN ac.cnt >= 3 THEN 'above' ELSE 'below' END AS segment,
  COUNT(*) AS users,
  ROUND(100.0 * SUM(ur.retained) / COUNT(*), 2) AS retention_pct
FROM user_ret ur
JOIN users u ON ur.user_id = u.user_id
LEFT JOIN action_counts ac ON ur.user_id = ac.user_id
GROUP BY u.acquisition_source, segment
ORDER BY u.acquisition_source, segment;
```

**План/тариф.** Платящие пользователи удерживаются лучше по определению. Проверить, что magic number работает внутри каждого тарифа отдельно.

**Время регистрации.** Сезонность, маркетинговые кампании, изменения продукта. Разбить когорты по месяцам и убедиться, что корреляция стабильна.

### Шаг 5. Проверка каузальности через A/B тест

Корреляция не доказывает причинно-следственную связь. Единственный способ подтвердить, что действие вызывает retention: провести эксперимент.

Дизайн A/B теста:
- **Контроль:** стандартный онбординг.
- **Тест:** онбординг, который подталкивает к magic number действию (подсказки, упрощённый flow, гамификация).
- **Метрика:** 30-day retention.
- **Размер выборки:** рассчитать через формулу или калькулятор (Evan Miller, Optimizely).

Для разрыва в retention 20 п.п. (30% vs 50%) при alpha=0.05 и power=0.8 минимальная выборка — около 95 пользователей на группу. Для разрыва в 5 п.п. (30% vs 35%) потребуется уже около 1 400 на группу.

Если A/B тест подтверждает: группа с подталкиванием показывает значимо более высокий retention, magic number валиден. Можно перестраивать онбординг вокруг него.

## Мониторинг в продакшене

Найденный magic number требует [мониторинга](/ru/blog/llm-observability-langfuse/). Два ключевых дашборда:

### Activation rate

Доля новых пользователей, достигших magic number за активационное окно:

```sql
SELECT
  DATE_TRUNC('week', u.created_at) AS cohort_week,
  COUNT(DISTINCT u.user_id) AS total_users,
  COUNT(DISTINCT CASE WHEN ac.cnt >= 3 THEN u.user_id END)
    AS activated_users,
  ROUND(
    100.0 * COUNT(DISTINCT CASE WHEN ac.cnt >= 3 THEN u.user_id END)
    / COUNT(DISTINCT u.user_id), 2
  ) AS activation_rate
FROM users u
LEFT JOIN (
  SELECT e.user_id, COUNT(*) AS cnt
  FROM events e
  JOIN users u2 ON e.user_id = u2.user_id
  WHERE e.event_name = 'invite_teammate'
    -- только действия в активационном окне (14 дней от регистрации)
    AND e.event_timestamp BETWEEN u2.created_at
      AND u2.created_at + INTERVAL '14 days'
  GROUP BY e.user_id
) ac ON u.user_id = ac.user_id
WHERE u.created_at >= NOW() - INTERVAL '12 weeks'
  AND u.created_at < NOW() - INTERVAL '2 weeks'
GROUP BY cohort_week
ORDER BY cohort_week;
```

Падение activation rate — сигнал о проблеме в онбординге или изменении аудитории.

### Стабильность корреляции

Ежемесячно пересчитывать корреляцию magic number с retention. Продукт меняется, аудитория меняется, magic number может сдвинуться. Действие, которое было критичным полгода назад, может потерять значимость после редизайна.

## Типичные ошибки

**Принять корреляцию за каузацию.** Пользователи, которые создали 10 проектов за первую неделю, вероятно, пришли с сильным намерением. Если заставить всех создать 10 проектов, retention не обязательно вырастет.

**Игнорировать размер выборки.** Magic number с retention 95% на 12 пользователях ничего не стоит. Нужно минимум 100 пользователей в каждой группе, лучше 500+.

**Фиксировать magic number навсегда.** Facebook нашёл "7 друзей" в 2009. В 2026 их magic number наверняка другой. Пересчёт каждый квартал.

**Оптимизировать под метрику, а не под ценность.** Если magic number — "отправить 5 сообщений", задача не в том, чтобы заставить отправлять 5 пустых сообщений. Задача — помочь пользователю получить ценность, которую он получает после 5 реальных сообщений.

**Путать активацию и привычку.** Magic number описывает порог активации. Дальше работает retention loop. Пользователь прошёл порог, но не нашёл причину возвращаться каждую неделю — retention всё равно упадёт.

## С чего начать

1. Выгрузить все события за последние 6 месяцев с user_id и timestamp.
2. Построить таблицу retention (запрос из раздела "Определение retention").
3. Запустить корреляционный анализ по всем событиям.
4. Передать результаты в AI с промптом №1 для интерпретации.
5. Визуализировать ТОП-5 кандидатов, найти точку перелома.
6. Проверить confounders (источник, план, сезонность).
7. Запустить A/B тест с подталкиванием к magic number.
8. Настроить мониторинг activation rate и стабильности корреляции.

Весь процесс от выгрузки до первых результатов A/B теста занимает 3–6 недель. Корреляционный анализ — 1–2 дня. Основное время уходит на набор выборки для эксперимента.

Magic number — не серебряная пуля. Это инструмент фокусировки: вместо размытого "улучшить онбординг" появляется конкретная цель с измеримым результатом. Продукт, который знает свой magic number, направляет каждый новый экран, каждый email и каждое push-уведомление на достижение одного числа. И измеряет, работает ли это.

---

*Нужна помощь с поиском magic number и продуктовой аналитикой? Я помогаю стартапам внедрять AI-решения и строить продукты — [belov.works](https://belov.works).*
