← Все статьи
10 июня 202610 минПрактикаctwa · whatsapp attribution · capi · click-to-whatsapp · meta ads · воронка аналитика

Как отследить click-to-WhatsApp рекламу до продажи: pipeline атрибуции

Полный технический pipeline CTWA-атрибуции: от парсинга ctwa_clid из webhook до CAPI-события при продаже. Без BSP, с кодом, шаблоном дашборда и реальными цифрами CPL.

Степан Милахин

Почему Ads Manager врёт: «conversations started» ≠ продажа

Откройте Ads Manager и посмотрите на свою CTWA-кампанию. Meta покажет вам красивую цифру: «50 conversations started». Вы подумаете, что получили 50 лидов. На практике до 90% людей, кликнувших на CTWA-рекламу, вообще не отправляют первое сообщение. Они открыли чат, посмотрели и закрыли. Meta уже засчитала «conversation», хотя разговора не было.

Это ловушка, на которую попадается большинство рекламодателей. «Messages started» в Ads Manager это не конверсия. Это технический факт открытия чата. Разница между «открыл WhatsApp» и «записался на услугу» может быть в 10-15 раз. Когда вы оптимизируете кампанию по этой метрике, алгоритм честно находит людей, которые кликают и открывают чат. Но ему всё равно, купят они или нет, потому что вы не сообщили ему, что значит «купил».

Вот пример из практики. У одного нашего клиента, автодилера Hyundai, Ads Manager показывал «50 начатых диалогов» за неделю. Когда мы посмотрели реальные данные из CRM, оказалось: 8 дошли до квалификации, 2 до сделки. Остальные 42 написали «привет», задали один вопрос и пропали. Алгоритм Meta не видел этой разницы, потому что никто не отправлял ему server-side events.

Без CAPI (Conversions API) алгоритм Meta не знает, кто купил, а кто просто написал «привет». Advantage+ оптимизирует на мусор: ищет людей, похожих на тех, кто открывает чаты, а не на тех, кто платит. Вы получаете дешёвые «диалоги» с нулевой конверсией, и не понимаете, почему продаж нет при «хороших» цифрах в отчёте.

Проблема глубже, чем кажется. Ads Manager не видит, что происходит после открытия чата. Квалификация, переговоры, назначение встречи, оплата: для Meta это чёрный ящик. Единственный способ его открыть: отправлять события из вашего бэкенда обратно в Meta через CAPI. Тогда алгоритм начинает понимать, какой клик привёл к продаже, и перестраивает оптимизацию. Разница ощутима: через 2-3 недели стабильного CAPI-фидбэка стоимость лида падает на 30-50%.

Анатомия ctwa_clid: что это, где живёт и почему исчезает

Когда человек кликает на CTWA-рекламу и открывает чат в WhatsApp, Meta передаёт в webhook два поля, которые большинство разработчиков игнорируют. Первое: source_id, это external campaign_id Meta, связывает контакт с конкретной кампанией. Второе: ctwa_clid, уникальный click ID, связывающий конкретный клик с конкретным пользователем. Оба поля приходят внутри объекта referral в payload первого сообщения.

Ключевое слово здесь: первого. ctwa_clid существует только в первом webhook-сообщении от пользователя. Не во втором, не в третьем, только в первом. Если ваш бэкенд не распарсил referral-объект при ingest первого сообщения и не сохранил эти данные в контакт, атрибуция потеряна навсегда. Восстановить невозможно. Meta не пришлёт эти поля повторно. Это то, что я называю decay-проблемой ctwa_clid.

Большинство CRM и чат-платформ этот момент просто игнорируют. Они парсят текст сообщения, сохраняют имя и телефон, но referral-объект пропускают. Вы подключили Wati, Respond.io или ManyChat, настроили бота, всё работает, клиенты пишут. Но когда через месяц вы хотите понять, какая кампания привела этого клиента, данных нет. Потому что платформа не сохранила ctwa_clid в момент первого контакта.

Правильный подход: парсить referral при первом сообщении, сохранять source_id и ctwa_clid в запись контакта по принципу first-touch wins. Если у контакта уже есть атрибуция (например, он пришёл раньше из другого канала), не перезаписываем. Первое касание определяет источник. При создании лида атрибуция наследуется из контакта автоматически: campaign_id, campaign_name, ctwa_clid.

Позже, когда лид проходит квалификацию или закрывается в продажу, ctwa_clid используется при отправке server-side event через CAPI. Meta получает exact attribution: вот этот конкретный клик привёл к вот этой конкретной продаже. Без ctwa_clid CAPI-событие всё равно можно отправить (по телефону или email), но точность атрибуции будет значительно ниже.

Полный pipeline: webhook → extraction → CRM → CAPI

Вот как выглядит полный технический pipeline от клика до закрытия сделки. Четыре шага, каждый с конкретной реализацией. Ни один конкурентный гайд не даёт этот pipeline целиком, обычно останавливаются на «настройте CAPI» без объяснения как именно.

Шаг 1: приём webhook и extraction. WhatsApp Cloud API присылает POST на ваш endpoint при каждом входящем сообщении. В payload первого сообщения от нового контакта ищем объект referral. Внутри него два поля: source_id (campaign_id Meta) и ctwa_clid (click id). Если referral есть, извлекаем оба значения. Если нет (человек написал сам, не через рекламу), двигаемся дальше без атрибуции.

// Псевдокод: extraction из webhook payload
const message = body.entry[0].changes[0].value.messages[0];
const referral = message.referral;
if (referral) {
  attribution.source_id = referral.source_id;
  attribution.ctwa_clid = referral.ctwa_clid;
}

Шаг 2: first-touch сохранение. Создаём или обновляем контакт в CRM. Если у контакта ещё нет атрибуции, записываем source_id и ctwa_clid. Если атрибуция уже есть (контакт вернулся), не трогаем. First-touch wins. Это принципиальный момент: если перезаписывать на last-touch, вы потеряете информацию о том, какая кампания реально привела клиента.

Шаг 3: auto-inherit при создании лида. Когда бот или менеджер квалифицирует контакт и создаёт лид, атрибуция наследуется автоматически. Лид получает campaign_id, campaign_name и ctwa_clid из контакта. Не нужно заполнять вручную, не нужно спрашивать «откуда узнали». Данные уже есть.

Шаг 4: CAPI event при смене статуса. Когда лид переходит в статус qualified или won, отправляем server-side event через Meta Conversions API. В user_data передаём ctwa_clid, хешированные phone и email (SHA-256 по спецификации Meta). Endpoint: POST /{pixel_id}/events на Graph API.

// Псевдокод: CAPI event при закрытии сделки
await fetch(`https://graph.facebook.com/v21.0/${pixelId}/events`, {
  method: 'POST',
  body: JSON.stringify({
    data: [{
      event_name: 'Purchase',
      event_time: Math.floor(Date.now() / 1000),
      user_data: {
        ctwa_clid: lead.attribution.ctwa_clid,
        ph: [sha256(phone)],
        em: [sha256(email)]
      },
      custom_data: { value: lead.value, currency: 'KZT' }
    }]
  })
});

Четыре шага. Webhook парсит, контакт хранит, лид наследует, CAPI замыкает. Вся цепочка работает автоматически после начальной настройки.

CAPI без BSP: настройка на WhatsApp Cloud API напрямую

Стандартный путь подключения CAPI для WhatsApp: купить подписку на BSP (Business Solution Provider) типа Wati, Respond.io или AiSensy. Они дают готовый интерфейс, ботов, аналитику. Проблема в цене и зависимости. BSP берут $30-150 в месяц за один номер. На пяти клиентах это $150-750 в месяц. На WhatsApp Cloud API напрямую, без посредника, ваши расходы: серверное время (€5/мес за VPS или бесплатно на Vercel) плюс conversation fees Meta ($0.05-0.08 за marketing conversation). Разница на 5 клиентах за год выходит в шестизначные суммы в тенге.

Но дело не только в деньгах. Когда данные о воронке проходят через BSP, вы отдаёте контроль. При смене платформы данные не портируются. Для тех, кто осознанно строит digital-инфраструктуру под ключ, а не арендует чужую, это принципиальный момент. Вы владеете данными о продажах, а не Wati.

Для прямой интеграции CAPI нужен System User token. Тут частая ошибка: многие берут token из Events Manager. Этот token имеет read-only scope, он не может отправлять события. Нужен System User с scope ads_management на конкретный dataset (pixel). Создаётся через Business Manager → System Users → Generate New Token. Без правильного scope CAPI тихо возвращает 200 OK, но события не засчитываются. Отлаживать это без логов Events Manager можно долго.

Второй момент: хеширование PII. Meta требует, чтобы phone и email передавались в SHA-256 хеше. Не md5, не plain text, именно SHA-256. Телефон должен быть в формате E.164 (с кодом страны, без плюса): sha256('77001234567'). Email в нижнем регистре, без пробелов. Если хеширование неправильное, Meta не сопоставит событие с пользователем, и ваш CAPI-фидбэк будет бесполезен.

Третий момент: шифрование токенов в вашей БД. OAuth access tokens и System User tokens не должны лежать plain text. AES-256-GCM шифрование на уровне приложения, ключ в переменной окружения. Если кто-то получит доступ к вашей базе (SQL injection, бэкап на открытом S3), токены останутся зашифрованными.

Что CAPI-фидбэк делает с вашим CPL через 2-3 недели

Первые дни после подключения CAPI ничего не меняется. Алгоритм Meta собирает данные, анализирует, какие клики привели к каким событиям. Через 2-3 недели стабильного фидбэка начинается магия: стоимость лида падает на 30-50%. Meta перестаёт лить бюджет на «кликабельных, но не покупающих» и начинает искать людей, похожих на тех, кто реально заплатил.

Цифры из практики. У автодилера Hyundai CTWA-кампания давала $1.08 за диалог (Porter + EX5, Instagram placements). Для сравнения: лендинг с AI-ботом на том же трафике давал $12.46 за лида. Лендинг конвертил 4.8%, но каждый landing view стоил $0.59, и нужно было 21 просмотр на одного лида. CTWA оказалась в 12 раз выгоднее. Это не теория, это прямое A/B сравнение на одном и том же продукте и аудитории.

Есть ещё один фактор, который мало кто мониторит: скорость ответа как quality signal для алгоритма Meta. Когда бот отвечает за 5-10 секунд, Meta фиксирует хороший inbox response time у вашего бизнес-аккаунта. Алгоритм начинает показывать рекламу более ценным пользователям, потому что знает: здесь ответят быстро, experience будет хороший. CPL ползёт вниз без каких-либо изменений в самой рекламе.

Обратный эффект тоже работает. Если ваш менеджер отвечает через час, или бот сломался и висит, response time растёт. Meta это видит. 74% клиентов ожидают ответ менее чем за час, 51% хотят ответ за 15 минут. Ответ дольше 30 секунд коррелирует с деградацией качества аудитории. CPL растёт, а вы грешите на креативы. Это надо мониторить системно, не вручную. Алерт на response time > 30 секунд, дашборд с медианным временем ответа по дням, корреляция с CPL. Если вы видите, что CPL пошёл вверх без изменений в кампании, первое что стоит проверить: не сломался ли бот, не начал ли менеджер отвечать медленнее (о надёжности AI-агентов в production писал отдельно).

Замыкаем офлайн: Kaspi-перевод, наличные, оплата при встрече

Всё, что описано выше, работает отлично пока оплата проходит онлайн. Но для локального бизнеса в Казахстане (и в СНГ в целом) реальность другая: 70%+ оплат идут не через онлайн-эквайринг. Kaspi-перевод на карту, наличные при встрече, перевод на Kaspi QR после процедуры. Ни один стандартный инструмент не замыкает эту воронку автоматически.

Выглядит это так: клиент кликнул CTWA-рекламу, поговорил с ботом в WhatsApp, записался на услугу, пришёл, заплатил наличными. В CRM вы видите лида со статусом «записан». Но факт оплаты нигде не зафиксирован. Ads Manager не знает, что произошла продажа. CAPI-событие не отправлено. Алгоритм Meta по-прежнему не понимает, какой клик привёл к деньгам.

Решение простое по архитектуре, но требует дисциплины. В карточке лида есть два поля: value (сумма сделки) и margin (маржа). Когда менеджер или владелец переводит лида в статус «won», он фиксирует сумму. В этот момент система автоматически отправляет Purchase event через CAPI с этой суммой и ctwa_clid из атрибуции контакта. Цикл замкнут.

Дашборд воронки строится на этих данных. Сверху вниз: расход (тянется из Meta Ads API автоматически) → ожидаемая выручка (сумма value по открытым лидам) → фактическая выручка (по закрытым won) → маржа. Две колонки: «ожидаемые» по открытым сделкам и «фактические» по закрытым. Это даёт полную картину от рекламного бюджета до прибыли, даже когда клиент платит наличными при встрече.

Шаблон CTWA-дашборда: 7 метрик от impression до ROAS

CPM → CTR → message_rate (% кликнувших, реально написавших) → qualification_rate → close_rate → revenue → ROAS. Семь метрик, каждая показывает конкретное узкое место в воронке.

Message_rate здесь ключевая метрика, которую никто не считает. Разрыв между кликами и реальными сообщениями показывает качество креатива и pre-filled текста. Если message_rate ниже 15%, проблема не в таргете, а в том, что человек кликнул, увидел чат и не понял зачем писать. Эксперименты с welcome-сообщением дают разницу в конверсии в 2-3 раза: короткое и конкретное всегда бьёт длинное перечисление услуг.

Две валюты: расходы Meta приходят в USD (или валюте рекламного аккаунта), выручка в KZT. Конвертация через актуальный курс, не захардкоженный. Если курс зашит в код, через месяц ваш ROAS будет врать на 3-5%, а через полгода на 10%+.

Какие метрики тянутся автоматически: CPM, CTR, клики, message_rate (из webhook-данных), расход. Какие требуют ручного ввода: value при закрытии сделки, margin. Qualification_rate и close_rate считаются из соотношения статусов лидов в CRM.

Формулы:

  • message_rate = messages_started / link_clicks × 100%
  • qualification_rate = qualified_leads / messages_started × 100%
  • close_rate = won_deals / qualified_leads × 100%
  • ROAS = revenue / ad_spend (обе суммы в одной валюте после конвертации)

Ловушки: дубли лидов, learning phase reset и BSUID

Три независимых создателя лидов (quick-lead, AI-бот, auto-lead) плодят карточки на один контакт. Менеджер видит в CRM три записи на одного человека и не понимает, какая актуальная. Правило, к которому мы пришли через боль: один (tenant, contact) = один открытый лид в любой момент. Перед созданием нового лида проверяем, нет ли уже открытого на этот контакт. Если есть, работаем с существующим. Это касается и ботов: если AI-бот квалифицировал контакт, а quick-lead уже создал болванку, бот должен обновить существующую карточку, а не создавать вторую.

Learning phase reset: пауза рекламы больше 24 часов сбрасывает learning phase Meta. CPL утром понедельника ×2-3 от нормы. Из нашего опыта: CTWA-кампания с нормой $1.08/диалог выдавала $3.43 в понедельник утром после weekend pause. К вечеру нормализовалась, но нетто экономия за выходные минус разогрев получалась $30-50. Считайте заранее, стоит ли пауза того.

BSUID (июнь 2026): WhatsApp вводит username + Business Scoped User ID. CRM, завязанные на номер телефона как primary key, начнут плодить дубли контактов и ломать attribution-цепочки. Один пользователь = несколько identity. Если вы строите CRM сейчас, закладывайте двумерную identity-модель (phone + BSUID) до массового rollout.

Instagram CTWA растёт быстрее Facebook в СНГ и MENA, но все гайды написаны под Facebook. Другой формат креатива, другая аудитория, другие CPL-бенчмарки. Не экстраполируйте данные Facebook CTWA на Instagram напрямую.

Похожие статьи
Контакты

Расскажите о задаче — посмотрим, по пути ли нам

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