Как посчитать Last-Touch Attribution в SQL

Проверь себя · 1/3разбор после ответа
Есть таблицы payments(user_id) и refunds(user_id). Нужно получить пользователей, у которых был платёж, но не было ни одного возврата. Какой запрос корректнее всего описывает задачу?

Зачем Last-Touch

Last-touch — самая распространённая модель атрибуции: вся заслуга за конверсию отдаётся последнему каналу в пути пользователя. Это дефолт в Google Ads и Яндекс Метрике, потому что модель проста, понятна бизнесу и легко считается одним запросом.

У простоты есть цена: last-touch переоценивает каналы, которые закрывают сделку (ретаргетинг, брендовый и платный поиск по бренду), и недооценивает верх воронки — SEO, органику, контент, которые вообще привели человека. Поэтому на собесе маркетинг-аналитика её любят как отправную точку, но ждут, что вы назовёте ограничения и упомянете multi-touch как более честную альтернативу.

Формула

Last-Touch: последний канал в пути пользователя получает всю заслугу за конверсию

Идея в одном предложении: берём все касания пользователя до момента конверсии, сортируем по времени и приписываем конверсию тому каналу, что был последним. Ключевое ограничение — учитывать только касания, которые произошли до конверсии.

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

Исходные данные: touchpoints(user_id, channel, touched_at) — касания пользователя с каналами, и conversions(user_id, amount, converted_at) — сами конверсии с суммой.

WITH last_touch AS (
    SELECT
        c.user_id,
        c.amount,
        c.converted_at,
        (
            SELECT channel
            FROM touchpoints t
            WHERE t.user_id = c.user_id
              AND t.touched_at <= c.converted_at
            ORDER BY t.touched_at DESC
            LIMIT 1
        ) AS last_channel
    FROM conversions c
)
SELECT
    last_channel,
    COUNT(*) AS conversions,
    SUM(amount) AS attributed_revenue
FROM last_touch
GROUP BY last_channel
ORDER BY attributed_revenue DESC;

Здесь коррелированный подзапрос для каждой конверсии находит последнее касание до её момента (ORDER BY touched_at DESC LIMIT 1). Затем группируем по каналу и суммируем выручку, которую этот канал «закрыл».

По каналам

Тот же результат можно получить через оконную функцию — часто это читается чище и лучше оптимизируется:

WITH last_touch AS (
    SELECT
        c.user_id,
        c.amount,
        FIRST_VALUE(t.channel) OVER (
            PARTITION BY c.user_id
            ORDER BY t.touched_at DESC
        ) AS last_channel
    FROM conversions c
    JOIN touchpoints t ON t.user_id = c.user_id AND t.touched_at <= c.converted_at
)
SELECT
    last_channel,
    COUNT(DISTINCT user_id) AS conversions,
    SUM(amount) AS revenue
FROM last_touch
GROUP BY last_channel
ORDER BY revenue DESC;

FIRST_VALUE(...) OVER (PARTITION BY user_id ORDER BY touched_at DESC) для каждого пользователя берёт первый в порядке убывания времени канал, то есть самое позднее касание. JOIN с условием touched_at <= converted_at отсекает касания, случившиеся уже после конверсии.

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

Плюсы и минусы

Плюсы Минусы
Легко считать одним запросом Переоценивает низ воронки
Дефолт в большинстве платформ Недооценивает органику и SEO
Стабильный и воспроизводимый результат Игнорирует ассистирующие касания
Прямая измеримость по последнему клику Не показывает весь путь пользователя

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

Учитывать касания после конверсии. В окно должны попадать только касания до момента конверсии, иначе канал, «догнавший» уже купившего пользователя, получит чужую заслугу.

Считать direct за полноценное касание. Если пользователь пришёл напрямую, это last-touch или просто узнаваемость бренда? Часто direct исключают из атрибуции — это бизнес-решение, которое нужно проговорить.

Игнорировать окно атрибуции (lookback window). Касание месячной давности и касание двухлетней давности нельзя считать одинаково значимыми — задайте разумное окно (обычно 30–90 дней) и отсекайте всё старше.

Не определиться с несколькими конверсиями. Если пользователь совершил пять покупок, засчитывать last-touch к первой конверсии или к каждой? Ответ зависит от вопроса бизнеса — важно зафиксировать логику явно.

Не сравнивать first и last. Если первое и последнее касание совпадают — это single-touch путь, когда человек пришёл и сразу купил. Доля таких путей — полезный сигнал о зрелости воронки.

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

FAQ

Last-Touch — это стандарт?

Да, это дефолтная модель в большинстве рекламных платформ (Google Ads, Яндекс Метрика). Её выбирают за простоту и понятность: легко объяснить бизнесу и легко посчитать. Но как единственную модель её лучше не использовать.

В чём главные минусы Last-Touch?

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

Когда Last-Touch уместна?

Для транзакционных бизнесов с коротким циклом принятия решения — e-commerce, мобильные игры, импульсные покупки. Там путь короткий, и последнее касание действительно близко к решению. Для B2B и дорогих покупок с длинным циклом last-touch сильно искажает картину.

Last-Touch или multi-touch?

Multi-touch (linear, time-decay, U-shaped) честнее: он делит заслугу между всеми касаниями. Но он сложнее в расчёте и зависит от выбранной модели. Last-touch остаётся простым baseline, с которого удобно начинать, а затем сравнивать с multi-touch.

Считать ли direct за Last-Touch?

Зависит от бизнес-логики. Часто direct исключают: пользователь вернулся напрямую, потому что бренд уже создал узнаваемость раньше, а не потому что «прямой заход» его убедил. Решение нужно зафиксировать явно и применять его последовательно.