Как посчитать K-factor в SQL
Карьерник — квиз-тренажёр в Telegram с 1500+ вопросами для собесов аналитика. SQL, Python, A/B, метрики. Бесплатно.
Зачем K-factor
K-factor — это количественное измерение виральности продукта. Каждый новый пользователь приводит в среднем X друзей, каждый из них — ещё X и так далее. K = 1 → продукт растёт экспоненциально без единого маркетингового рубля. K = 0.5 → органического роста нет, надо платить.
На собеседовании для growth-команд (Notion, Miro, Slack-подобные) это одна из главных тем. «Посчитай K-factor у нас», «как поменять, чтобы K > 1», «какое cycle time разумно». Без понимания формулы K = invites × conversion вы не пройдёте.
Типичные ошибки в подсчёте: считать приглашения, а не регистрации (один invite послать легко, но конверсия 5%), игнорировать cycle time (K=1 с циклом 30 дней значит удвоение через 30 дней, не сразу), не сегментировать по каналу share (WhatsApp vs Telegram vs ссылка).
В статье — готовые SQL-запросы:
- Базовый K-factor = invites per user × conversion rate
- Invites per active user
- Conversion: % приглашений, приведших к регистрации
- Cycle time — сколько дней от invite до signup
- K-factor по каналам share
- Cohort K-factor (улучшается ли)
Схема: users(id, invited_by_user_id, signup_at), invites(invite_id, sender_user_id, sent_at, converted_user_id).
1. Формула
K-factor = Invites per user × Conversion rate- Invites per user: среднее приглашений на активного пользователя
- Conversion: % приглашений, ставших регистрациями
2. Базовый K-factor
WITH invites_sent AS (
SELECT
sender_user_id,
COUNT(*) AS invites_sent
FROM invites
WHERE sent_at >= NOW() - INTERVAL '30 days'
GROUP BY sender_user_id
),
active_users AS (
SELECT COUNT(DISTINCT user_id) AS active
FROM events
WHERE event_at >= NOW() - INTERVAL '30 days'
),
conversion_stats AS (
SELECT
COUNT(*) AS total_invites,
COUNT(converted_user_id) AS converted_invites
FROM invites
WHERE sent_at >= NOW() - INTERVAL '30 days'
)
SELECT
-- среднее invites на активного
SUM(invites_sent)::FLOAT / (SELECT active FROM active_users) AS invites_per_user,
-- conversion
(SELECT converted_invites::FLOAT / NULLIF(total_invites, 0) FROM conversion_stats) AS conversion,
-- K-factor
SUM(invites_sent)::FLOAT / (SELECT active FROM active_users) *
(SELECT converted_invites::FLOAT / NULLIF(total_invites, 0) FROM conversion_stats) AS k_factor
FROM invites_sent;3. Invites per user
SELECT
DATE_TRUNC('week', sent_at) AS week,
COUNT(*)::FLOAT / COUNT(DISTINCT sender_user_id) AS invites_per_sender
FROM invites
GROUP BY 1
ORDER BY 1;Но лучше — на активного пользователя (не только отправителя):
WITH active AS (
SELECT DISTINCT DATE_TRUNC('week', event_at) AS week, user_id
FROM events
),
sent AS (
SELECT DATE_TRUNC('week', sent_at) AS week, sender_user_id AS user_id, COUNT(*) AS cnt
FROM invites
GROUP BY 1, 2
)
SELECT
a.week,
SUM(COALESCE(s.cnt, 0))::FLOAT / COUNT(DISTINCT a.user_id) AS invites_per_active_user
FROM active a
LEFT JOIN sent s USING (week, user_id)
GROUP BY a.week
ORDER BY a.week;4. Conversion rate приглашений
SELECT
DATE_TRUNC('month', sent_at) AS month,
COUNT(*) AS invites_sent,
COUNT(converted_user_id) AS conversions,
100.0 * COUNT(converted_user_id) / COUNT(*) AS conversion_pct
FROM invites
GROUP BY 1
ORDER BY 1;5. Cycle time — сколько от invite до signup
SELECT
AVG(EXTRACT(EPOCH FROM (u.signup_at - i.sent_at)) / 86400) AS avg_cycle_days,
PERCENTILE_CONT(0.5) WITHIN GROUP (
ORDER BY EXTRACT(EPOCH FROM (u.signup_at - i.sent_at)) / 86400
) AS median_cycle_days
FROM invites i
JOIN users u ON u.id = i.converted_user_id
WHERE i.converted_user_id IS NOT NULL;Короткий cycle (< 1 дня) + K > 1 → взрывной рост. Длинный cycle — даже K > 1 растёт медленно.
6. K-factor по каналам share
WITH invites_by_channel AS (
SELECT
share_channel,
COUNT(*) AS sent,
COUNT(converted_user_id) AS conversions
FROM invites
GROUP BY share_channel
)
SELECT
share_channel,
sent,
conversions,
100.0 * conversions / sent AS conversion_pct
FROM invites_by_channel
ORDER BY conversion_pct DESC;WhatsApp обычно конвертит лучше email. Email лучше SMS. Copy-link хуже.
7. K-factor по cohort
WITH cohorts AS (
SELECT id AS user_id, DATE_TRUNC('month', signup_at) AS cohort
FROM users
),
cohort_invites AS (
SELECT
c.cohort,
COUNT(DISTINCT c.user_id) AS cohort_size,
COUNT(i.invite_id) AS total_invites,
COUNT(i.converted_user_id) AS converted
FROM cohorts c
LEFT JOIN invites i ON i.sender_user_id = c.user_id
GROUP BY c.cohort
)
SELECT
cohort,
total_invites::FLOAT / cohort_size AS invites_per_user,
converted::FLOAT / NULLIF(total_invites, 0) AS conversion,
total_invites::FLOAT / cohort_size *
converted::FLOAT / NULLIF(total_invites, 0) AS k_factor
FROM cohort_invites
ORDER BY cohort;8. K-factor для виральной петли
Если растите, отслеживайте unit-dynamics:
users_next_month = users × K (если K < 1, равновесие)При K = 0.5 и cycle 30 дней:
- Месяц 1: 100
- Месяц 2: 100 + 50 = 150
- Месяц 3: 150 + 75 = 225
- Но это рост, а не виральность (один user приводит <1 в долгую).
Частые ошибки
Считать invites, а не converted invites
K = invites × conversion, не просто invites.
Игнорировать cycle time
K = 1 с cycle year ≠ K = 1 с cycle day.
Не учитывать active vs all users
Invites per user от неактивных = разбавление.
Considering self-invites
Пользователи могут приглашать себя со второго аккаунта → фильтр по FK / IP.
Связанные темы
FAQ
K > 1 реально?
Редкость. Большинство успешных продуктов K = 0.3-0.7.
K-factor для B2B?
Да. Slack, Notion, Figma растут через invites (seats).
Cycle time влияет?
Критично. K=1 с циклом 30 дней ≠ K=1 с циклом 1 день.
Как повысить K?
Два рычага: invites per user (больше мотивации) + conversion (лучший onboarding для приглашённых).
Тренируйте SQL — откройте тренажёр с 1500+ вопросами для собесов.