Как посчитать Uninstalls в SQL

Проверь себя · 1/3разбор после ответа
Нужно получить 5 самых дешёвых товаров категории 'electronics' из таблицы products. Какой запрос верный?

Зачем считать uninstalls

Удаление приложения — самый честный сигнал «не понравилось». Пользователь может месяцами не открывать приложение, но пока оно висит на телефоне, есть шанс его вернуть пушем или письмом. Удаление обрывает эту связь окончательно: ни пуш прислать, ни ремаркетинг настроить. Поэтому uninstall rate — одна из критических метрик здоровья мобильного продукта.

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

Формула

Uninstall Rate = uninstalls / installs × 100%

Базовый расчёт

Самый простой вариант — помесячно посчитать установки и удаления из таблицы событий и получить долю:

WITH stats AS (
    SELECT
        DATE_TRUNC('month', event_time) AS month,
        COUNT(*) FILTER (WHERE event_type = 'install')   AS installs,
        COUNT(*) FILTER (WHERE event_type = 'uninstall') AS uninstalls
    FROM app_events
    WHERE event_time >= '2026-01-01'
    GROUP BY 1
)
SELECT
    month,
    installs,
    uninstalls,
    uninstalls::NUMERIC * 100 / NULLIF(installs, 0) AS uninstall_rate_pct
FROM stats
ORDER BY month;

NULLIF(installs, 0) защищает от деления на ноль, если в каком-то месяце установок не было. Но у такого «наивного» расчёта есть подвох: установки одного месяца могут удаляться в следующем, поэтому доля в лоб занижает реальный отток. Честнее считать по когортам — об этом ниже.

Uninstall rate по когортам

Когортный разрез показывает, когда происходят удаления: группируем пользователей по неделе установки и смотрим, какая доля удалила приложение в течение 7 и 30 дней от своей установки, а не по календарному месяцу.

WITH cohort_installs AS (
    SELECT
        device_id,
        DATE_TRUNC('week', event_time) AS install_week,
        event_time AS install_time
    FROM app_events
    WHERE event_type = 'install'
),
uninstalls AS (
    SELECT
        device_id,
        event_time AS uninstall_time
    FROM app_events
    WHERE event_type = 'uninstall'
)
SELECT
    c.install_week,
    COUNT(DISTINCT c.device_id) AS installs,
    COUNT(DISTINCT CASE
        WHEN u.uninstall_time <= c.install_time + INTERVAL '7 days'
        THEN c.device_id
    END) AS uninstalled_7d,
    COUNT(DISTINCT CASE
        WHEN u.uninstall_time <= c.install_time + INTERVAL '30 days'
        THEN c.device_id
    END) AS uninstalled_30d
FROM cohort_installs c
LEFT JOIN uninstalls u ON u.device_id = c.device_id
GROUP BY c.install_week
ORDER BY c.install_week;

Такой расчёт сравнивает каждую когорту с самой собой и убирает искажение из базового варианта: удаление всегда привязано к дате установки конкретного устройства, а не к календарю.

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

Время до удаления

Ещё полезнее — распределение по времени жизни: через сколько дней после установки люди удаляют приложение. Джойним установку и первое последующее удаление того же устройства и раскладываем разницу по корзинам.

WITH paired AS (
    SELECT
        i.device_id,
        i.event_time AS install_time,
        u.event_time AS uninstall_time,
        EXTRACT(EPOCH FROM (u.event_time - i.event_time)) / 86400 AS days_to_uninstall
    FROM app_events i
    JOIN app_events u ON u.device_id = i.device_id
        AND u.event_time > i.event_time
        AND u.event_type = 'uninstall'
    WHERE i.event_type = 'install'
)
SELECT
    CASE
        WHEN days_to_uninstall <= 1  THEN '< 1 day'
        WHEN days_to_uninstall <= 7  THEN '1-7 days'
        WHEN days_to_uninstall <= 30 THEN '8-30 days'
        WHEN days_to_uninstall <= 90 THEN '31-90 days'
        ELSE '90+ days'
    END AS bucket,
    COUNT(*) AS uninstalls
FROM paired
GROUP BY 1
ORDER BY 1;

Форма распределения сразу подсказывает диагноз. Если 60% удалений приходится на первые сутки — почти наверняка сломан онбординг или реклама приводит нецелевую аудиторию. Если пик размазан по 30–90 дням — скорее вопрос удержания и ценности, а не первого впечатления.

Связать метрики удаления с полной картиной удержания и активации помогает практика на реальных задачах — например, в тренажёре на kariernik.ru.

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

Ошибка 1. Трекинг самого события. iOS и Android не сообщают об удалении в реальном времени. Стандартный способ детекта — тихий (silent) пуш: если устройство перестаёт отвечать и токен становится невалидным, приложение считается удалённым. Отсюда следует задержка в несколько дней, и это надо закладывать в отчёты.

Ошибка 2. Переустановка. Пользователь удалил приложение и поставил заново через неделю. Считать это как одну установку или две — вопрос определения, но он должен быть зафиксирован явно, иначе метрики разъедутся между командами.

Ошибка 3. Кросс-девайс. iPhone удалил, iPad оставил. По одному устройству это удаление, но пользователь остался с вами — по человеку это не отток. Если считать по устройствам, а выводы делать про пользователей, получите искажение.

Ошибка 4. Считать краш за удаление. Падение приложения — это не удаление. Это разные события с разными причинами; смешивать их — значит завышать отток и гоняться не за той проблемой.

Ошибка 5. Рассинхрон периодов. Сравнивать установки месяца X с удалениями того же месяца X некорректно: установки месяца X могут удаляться в следующих месяцах. Именно поэтому для честной картины считают по когортам.

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

FAQ

Какой uninstall rate считается нормальным?

Ориентиры для мобильных приложений: к первому дню (D1) удаляют 30–50%, к D7 — 50–70%, к D30 — 70–85%. Мобильный трафик сам по себе даёт высокий отток, поэтому важнее не абсолютное число, а динамика между когортами и сравнение с вашей же историей.

Как вообще обнаружить удаление?

Чаще всего через тихий пуш: сервер шлёт невидимое пользователю уведомление, и если устройство перестаёт подтверждать доставку (токен помечается невалидным), приложение считается удалённым. Именно так работают атрибуционные платформы вроде AppsFlyer и Adjust. Из-за этого детект всегда с задержкой в несколько дней.

Чем удаление отличается от неактивности?

При удалении приложения на устройстве больше нет — вернуть пользователя можно только повторной установкой. Неактивный пользователь приложение сохранил, просто не открывает; его ещё реально реактивировать пушем, письмом или обновлением. Это принципиально разные состояния оттока.

Каковы главные причины удалений?

Обычно это: плохое первое впечатление и сломанный онбординг; чистка памяти на устройстве; переход на приложение-замену; спам пушами. Первая причина — самая управляемая продуктом, поэтому и разрез «время до удаления» так важен.

Есть ли аналог удаления в вебе?

В вебе понятия «удаление» нет — там ближайший аналог это отказ (bounce) и невозврат пользователя. Метрика удаления уникальна для мобильных приложений именно потому, что приложение физически установлено на устройстве.