new-lvl.pro · Кейсы · A/B
Кейс // 12 мин чтения

Конверсия выросла на +9%,
а revenue упал на −3%

Синтетический разбор реалистичной ситуации: тестировали upgrade-кнопку в SaaS, целевая метрика выросла, общая выручка просела. Разбираем, как ловили каннибализацию между Free и Pro сегментами и какие guard-метрики помогли бы поймать это раньше.

Контекст: SaaS-инструмент и 2.4M юзеров

Продукт — SaaS для команд (что-то между Notion и Figma). Подписки трёх уровней: Free, Pro ($12/мес), Team ($24/мес за seat). Команда роста копает в направлении «как лучше монетизировать Free-юзеров»: их 2 млн, доля апгрейдов в Pro — 0.22% в неделю.

Продукт
SaaS для команд, тарифы Free / Pro / Team
Аудитория
2.4M активных в месяц: 2M Free + 360K Pro + 40K Team
Цель квартала
+15% к Free→Pro конверсии
Гипотеза
«Юзеры не апгрейдятся, потому что кнопка спрятана в настройках. Если показать в верхнем меню — клики и конверсия вырастут»

Гипотеза разумная: апгрейд действительно был на третьем экране настроек. Решили выкатить заметную плашку прямо в шапке — кнопку Upgrade your workspace →, ведущую на страницу /plans, где можно выбрать тариф.

Что и как мерили

Сплит — стандартный 50/50 на платформенном уровне (по user_id, иначе говоря — на всех юзерах в системе, не только Free). Длительность — 14 дней, пилот первые 3 дня на 5% трафика. MDE по целевой — относительно скромные 5%.

Целевая метрика
CTR кнопки Upgrade и Free→Pro conversion за 14 дней
Сплит
50/50 по user_id, по 1.2M юзеров в каждой ячейке
Guard-метрики (что объявили)
CR онбординга, время до первого ценного действия — обе должны не упасть
Длительность
14 дней (по калькулятору sample-size для MDE 5%)
// Уже видна ошибка
Целевая метрика и guard-метрики поставлены только на Free-сегмент — потому что эксперимент «про монетизацию Free». Revenue per user по всем юзерам в ячейке (включая Pro и Team) — никто не отслеживал. Сюрприз ждёт впереди.

Промежуточный замер: всё хорошо

День 7 / 14 · трафика набралось 50%

Через неделю смотрят промежуточный дашборд. Целевая радует:

CTR кнопки Upgrade (Free)
+8.6%
p < 0.01
Растёт, как и хотели
Free → Pro conversion
+11.3%
p = 0.02
Уже бьёт цель квартала
CR онбординга
+0.4%
не значимо
Guard в норме

Команда роста в чате пишет «пилотный замер красивый, идём до конца теста и потом раскатываем». Никто не спорит, продакт ставит лайк. Эксперимент продолжается ещё 7 дней.

Финальный замер: что-то не так

День 14 / 14 · финал теста

Финальный отчёт перед раскаткой. Аналитик готовит апдейт и решает заодно «прихватить» revenue per user — не как формальный guard, а просто чтобы было красивее в презентации. И там:

CTR кнопки Upgrade (Free)
+9.2%
p < 0.01
Цель достигнута
Free → Pro conversion
+12.1%
p < 0.01
+27 апгрейдов в день
Revenue per user (по всем)
−2.9%
p = 0.04
Совсем не ожидали

Картина странная: целевая выросла, побочка на guard-метриках Free — норма, а общий revenue per user (через все сегменты в ячейке) упал. И статсиг.

Первая реакция команды: «наверное, статистический шум, давайте раскатим, на полной выборке выровняется». Аналитик берёт паузу — на пятницу вечером ничего не катить, разбираемся в понедельник.

Понедельник: четыре гипотезы

В понедельник аналитик раскладывает диагностику. Алгоритм — стандартный для «метрика упала»: от дешёвых проверок к дорогим. Подробно про подход — в статье «Декомпозиция метрики».

# Гипотеза Что проверял Вердикт
H1 Шум данных / sample ratio mismatch Доли control/treatment по плану (Free/Pro/Team) — 49.97% / 50.03%, как и должно быть не он
H2 Возвраты и refunds выросли в treatment Refund-таблица: control 0.21%, treatment 0.20% — нет связи с тестом не он
H3 Изменения цен / промо в период теста Никаких прайсинговых изменений за 14 дней не было — ни глобально, ни по сегментам не он
H4 Сегмент Pro/Team в treatment вёл себя по-другому Срез revenue по плану: Free одинаково, Pro −4.8%, Team −1.2% в нём дело

Стоп. Сегмент Pro в treatment просел на 4.8%. Но эксперимент задумывался про Free-юзеров. Pro вообще не должны были «увидеть» тест.

Аналитик идёт в код экспериментальной системы и обнаруживает простое: плашка Upgrade your workspace рисовалась через layout-компонент, и условие показа было только variant === 'treatment'. Без проверки текущего тарифа. То есть Pro-юзеры в treatment-ячейке тоже видели плашку «Upgrade your workspace», и часть из них кликала — кто из любопытства, кто думая что это про upgrade в Team.

Куда вёл клик? На страницу /plans, где честно отрисовывались все три тарифа — Free, Pro, Team — с кнопкой «Switch to this plan» под каждым. Дальше — следующий SQL.

SQL, который раскрыл картину

Аналитик собирает воронку «по тарифу на момент захода» × «куда переключился по итогу 14 дней» в обеих ячейках:

downgrade_funnel.sql
WITH entry AS (
  -- тариф на старте теста
  SELECT user_id, plan_at_start, ab_group
  FROM ab_assignments
  WHERE experiment = 'upgrade_banner_v1'
), final_plan AS (
  -- тариф на 14-й день
  SELECT user_id, plan AS plan_at_end
  FROM subscriptions_snapshot
  WHERE snapshot_date = '2026-04-28'
)
SELECT
  e.ab_group,
  e.plan_at_start,
  f.plan_at_end,
  COUNT(*) AS users,
  ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER (
    PARTITION BY e.ab_group, e.plan_at_start
  ), 2) AS pct
FROM entry e
JOIN final_plan f USING (user_id)
GROUP BY e.ab_group, e.plan_at_start, f.plan_at_end
ORDER BY e.ab_group, e.plan_at_start, f.plan_at_end;

Что видим в результатах:

Стартовый план Куда ушёл Control Treatment
Free → Pro 0.22% 0.247% (+12%)
Pro остался Pro 99.5% 96.7%
Pro → Team (upgrade) 0.3% 0.4%
Pro → Free (downgrade) 0.2% 2.9% (×14)
// открытие
Pro→Free downgrade вырос в 14 раз
Pro-юзеры в treatment кликали на плашку Upgrade your workspace, попадали на /plans — и впервые за всё время видели Free-план «в явном виде» с понятной кнопкой «Switch». Часть из тех, кто давно сомневался в подписке, нажимала «а зачем я плачу» и переходила на Free. То, что задумывалось как фича роста для Free, превратилось в downgrade-канал для Pro.

Считаем удар по выручке. В каждой ячейке 200К Pro-юзеров. Лишних downgrade в treatment: (2.9% − 0.2%) × 200K ≈ 5400 юзеров. Каждый — это −$12/мес повторяющегося дохода. Месячная потеря: ≈ $65 000. Это и тащит revenue per user вниз на 2.9%, потому что по абсолютным деньгам Pro весит во много раз больше, чем мелкий Free→Pro прирост.

Что починили и что добавили в процесс

В понедельник вечером эксперимент откатывают. Команда садится решать в три приёма: что сделать с самой фичей, что — с этим конкретным A/B, и что — на уровне процесса.

1. Сама фича

Очевидное: добавить условие plan === 'free' на серверной стороне. Плашка показывается только Free-юзерам. Через 3 дня перезапуск с этим гейтом — целевая по-прежнему растёт (+8.4% к CTR, +11.7% к Free→Pro), а revenue per user в треатменте теперь нулевой к контролю. Раскатка одобрена.

2. Этот конкретный A/B

Перепроверили все недавние тесты этой команды на ту же ошибку: плашки и баннеры в layout-уровне без сегментного гейта. Нашли ещё два — оба не давали такого катастрофического эффекта, но в одном тоже была лёгкая каннибализация (∼0.5% к downgrade). Оба переписали.

3. Процесс

Главный артефакт после кейса — обновлённый чек-лист дизайна A/B. До этого guard-метрики формулировались как «что не должно сломаться у целевого сегмента». После кейса — добавили обязательный пункт.

Guard-метрики: чек-лист после кейса
Целевая метрика на целевом сегменте. Та, ради которой эксперимент.
Guard на целевом сегменте. «Что не должно сломаться у тех, на кого мы целились»: воронка, retention, CR онбординга.
Guard на «соседних» сегментах. Если тест в принципе может коснуться других пользователей — посчитать по ним отдельные guard. Pro / Team / новые / старые.
Глобальный guard на revenue per user. Это ловит каннибализацию между сегментами и даунгрейды. Дешёвая страховка.
Guard на «обратные» действия. Если фича про upgrade — следи за downgrade. Если про signup — за churn. Если про активацию — за uninstall. Симметричный полюс почти всегда есть.
Изоляция эффекта по плану/сегменту в коде. Если эксперимент задуман только для Free — гейт в коде, а не «на словах в Confluence».

Что стоит унести из этого кейса

Кейс на собесе обычно сводится к одной фразе: «эффект на воронке ≠ эффект на бизнесе». Это правда, но мне нравится более операционная формулировка — её можно сразу применить.

Урок 01
У каждой growth-фичи есть симметричный риск
Ускорил signup → следи за churn. Сделал upgrade ярче → следи за downgrade. Активируешь → следи за uninstall. Всегда есть «обратная сторона», и если фича задевает оба полюса, эффект может уйти в ноль.
Урок 02
Guard-метрики — на соседних сегментах, не только на целевом
Тест «про Free» — но если эксперимент на платформенном уровне, Pro и Team тоже могут быть задеты. Заведи им отдельные guard. Дешёвая защита, всё считается тем же запросом.
Урок 03
Глобальный revenue per user — самый недооценённый guard
Целевые метрики по сегментам — узкие, можно пропустить «дыру в соседнем сегменте». Revenue per user по всей ячейке — широкий и ловит каннибализацию автоматически. Он должен быть в каждом эксперименте, влияющем на монетизацию.
Урок 04
Дерево метрик — не схема, а инструмент диагностики
Когда есть дерево метрик с явными ветками для Free / Pro / Team, каннибализацию ловишь не на 14-й день случайно, а сразу: смотришь дерево по сегментам, видишь, где задело лишнее.
// На собесе
Если вопрос «какие guard-метрики ты бы поставил для теста X» — не выпаливай «retention и churn». Структурируй: (1) guard на целевом сегменте, (2) guard на соседних, (3) guard на симметричное обратное действие, (4) глобальный revenue per user. Эта рамка превращает 30-секундный ответ в 2-минутный продуктовый разговор.

Связанные материалы

Главное про каннибализацию в A/B

Каннибализация — самая дорогая ошибка в продуктовых экспериментах: целевая метрика выглядит зелёной, фичу раскатывают, и только через месяц на квартальном ревью видят «странность» в общей выручке. Кейс выше — синтетический, но я видел почти такую же историю в реальных командах не один раз. Сценарий повторяется.

Защита — простая и почти бесплатная: обязательный набор guard-метрик на соседних сегментах и на «симметричном» обратном действии, плюс глобальный revenue per user в каждом тесте про монетизацию. Это никак не замедляет эксперимент и ловит почти всё, что может пойти не так в этой плоскости.

Следующий шаг: возьми последний A/B, который у тебя в работе, и проверь — есть ли в нём guard-метрика на сегменте, который вы «не имели в виду»? Если нет — добавь. Стоит 10 минут, спасает квартальное OKR.

АТ
Андрей Тарасенко
// Продуктовый аналитик · Авито · Ментор

Самые болезненные ошибки в A/B — те, где целевая метрика не врала, но мерили не тот контур. Кейс с каннибализацией — в моём топе для разбора с менти: показывает, что «значимый эффект» — это начало разговора, а не его конец.

Написать в Telegram