Перейти к содержанию

Keitaro и Facebook Conversions API (CAPI): настройка и скрипт

Как передавать конверсии из Keitaro в Facebook Conversions API: встроенная интеграция или скрипт, макросы S2S-постбэка, дедупликация с пикселем и проверка…

Keitaro и Facebook Conversions API (CAPI): настройка и скрипт

Facebook Conversions API (CAPI) передаёт конверсии в Meta с сервера, а не из браузера. В связке с Keitaro это работает так: партнёрская сеть сообщает трекеру о лиде или продаже, а Keitaro передаёт событие Lead или Purchase в пиксель через Conversions API. Сделать это можно встроенной интеграцией Keitaro или своим скриптом, который принимает S2S-постбэк. Пиксель на лендинге при этом остаётся, а одинаковый ID события не даёт Meta посчитать конверсию дважды.

Ниже оба способа, пошаговая настройка скрипта, макросы постбэка, проверка через тестовые события и частые ошибки. Скрипт можно скачать в конце статьи.

Обновлено 1 октября 2026. Мы переписали скрипт из первой версии статьи (май 2025) и нашли в старом архиве s2s серьёзные ошибки: часть данных не доходила до Meta, события уходили как пользовательские, а база с токенами открывалась по прямой ссылке. Если вы ставили архив s2s, сначала прочитайте раздел «Что было не так в версии 2025 года».

Содержание
  1. Как работает связка Keitaro и Conversions API
  2. Два способа: интеграция Keitaro или свой скрипт
  3. Что Meta нужно от серверного события
  4. Шаг 1. ID пикселя и токен Conversions API
  5. Шаг 2. Параметры кампании в Keitaro
  6. Шаг 3. Пиксель на лендинге с ID события
  7. Шаг 4. Установка скрипта
  8. Шаг 5. S2S-постбэк в Keitaro
  9. Шаг 6. Проверка через тестовые события
  10. Частые ошибки
  11. Что было не так в версии 2025 года
  12. База с токенами открывалась по ссылке
  13. Постбэк принимал запросы от кого угодно
  14. Часть данных не доходила до Meta
  15. Имя и телефон в адресе страницы
  16. Что сделать, если вы ставили архив s2s
  17. Скачать скрипт
  18. Частые вопросы
  19. Нужен ли пиксель, если настроен Conversions API?
  20. Чем встроенная интеграция Keitaro отличается от скрипта?
  21. Можно ли отправлять в один скрипт конверсии нескольких пикселей?
  22. Почему конверсия не появилась в Meta?
  23. Нужно ли хешировать IP и User-Agent?
  24. Можно ли отправить конверсию, которой больше недели?

Как работает связка Keitaro и Conversions API

Одна конверсия приходит в Meta двумя путями. Первый путь браузерный: человек оставил заявку, и пиксель на странице «спасибо» отправил событие Lead. Второй путь серверный: партнёрская сеть передала лид в Keitaro, а трекер переслал его в Conversions API сам или через скрипт.

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

Чтобы Meta не посчитала один лид дважды, оба события несут одинаковый ID. Для этого удобно взять subid клика в Keitaro: он есть и на лендинге, и в постбэке.

Схема: клик с fbclid, Keitaro, лендинг с пикселем и eventID, постбэк партнёрской сети, S2S-постбэк Keitaro, скрипт и серверное событие с тем же event_id
Схема boostclicks.tech.

Два способа: интеграция Keitaro или свой скрипт

В Keitaro есть встроенная интеграция Facebook Conversion. Она доступна на тарифах Advanced, Expert, Team и Enterprise. Настраивается в разделе «Интеграции»: имя, кампании, ID пикселя и токен, а в Mapping задаётся, какой статус Keitaro каким событием уйдёт в Meta. Кампания создаётся по шаблону источника Facebook.

По документации Keitaro интеграция отправляет fbc, fbp, IP и User-Agent клика, а также страну, регион и город по IP. Почту, телефон и имя она берёт из входящего постбэка партнёрской сети. Есть два условия. Конверсия уходит, только если у клика есть fbclid. И в поле URL Parameters в Ads Manager нельзя добавлять fbclid={fbclid}: Meta дописывает fbclid к ссылке сама, а макрос мешает трекеру его записать.

Документация Keitaro: удалите fbclid={fbclid} из URL Parameters, fbclid формируется автоматически
Документация Keitaro, «Facebook Conversions».

Ещё одна деталь из той же документации: адрес страницы (event_source_url) интеграция берёт из referrer и передаёт в хешированном виде. Meta же ждёт его открытым адресом, этот параметр в Conversions API не хешируется.

Свой скрипт пригодится, если:

  • тариф Keitaro ниже Advanced;
  • пикселей много, и удобнее передавать ID пикселя прямо в постбэке, чем заводить интеграцию на каждый;
  • нужен журнал с ответом Meta на каждое событие и тестовый код для отдельного постбэка;
  • часть кликов приходит без fbclid, а конверсии по ним тоже нужно отправлять: скрипт сопоставит их по IP, User-Agent и external_id.

Если интеграция вам доступна и условия подходят, начните с неё. Дальше в статье разбор скрипта, но шаги про пиксель на лендинге, дедупликацию и тестовые события нужны в обоих случаях.

Что Meta нужно от серверного события

Событие для Conversions API это JSON с несколькими обязательными полями и блоком данных о посетителе. По документации Meta обязательны event_name, event_time, action_source и user_data, а для событий сайта ещё event_source_url и client_user_agent. По данным о посетителе Meta находит человека, который кликнул по рекламе. Чем больше совпадений, тем выше оценка качества сопоставления (Event Match Quality, до 10 баллов) в Events Manager и тем точнее оптимизация.

Документация Meta: event_time не старше 7 дней, event_source_url обязателен для событий сайта
Документация Meta, Server Event Parameters.
ПолеЧто передатьОткуда в Keitaro
event_nameLead или Purchase, с заглавной буквыстатус конверсии
event_timeвремя конверсии в секундах Unix, не старше 7 дней{conversion_time:U}
action_sourcewebsiteконстанта
event_source_urlадрес страницы с конверсией, обязательноsub_id с адресом лендинга
event_idтот же ID, что у пикселя{subid}
client_user_agentбраузер посетителя, обязательно, без хеширования{user_agent}
client_ip_addressIP посетителя, без хеширования{ip}
fbcfb.1.время_клика_в_мс.fbclid, без хешированияfbclid и {date:U}
fbpзначение cookie _fbp, без хешированияsub_id, если сохраняете
external_id, ph, em, fn, ct, countryID, телефон, почта, имя, город, страна в SHA-256{subid}, sub_id из постбэка сети
value, currencyдля Purchase явная конечная выплата ≥ 0 и код валюты из трёх латинских букв{conversion_revenue}; валюта из currency или config.php
Таблица прокручивается вбок

Скрипт из статьи сам нормализует и хеширует данные по правилам из справочника Meta: почту и имя приводит к строчным буквам, в телефоне оставляет только цифры с кодом страны, из имени берёт первое слово, из города убирает пробелы и дефисы. Если сеть или трекер уже передают готовый SHA-256, скрипт не хеширует его второй раз.

Отдельно про fbc. Это идентификатор клика в формате fb.1.время.fbclid, где время указывается в миллисекундах, а сам fbclid нельзя менять, даже регистр букв. Если cookie _fbc вы не сохраняете, Meta разрешает собрать fbc на сервере из fbclid и времени, когда он впервые пришёл. Скрипт так и делает: берёт fbclid и время клика из Keitaro.

Документация Meta: ClickID чувствителен к регистру, creationTime в fbc указывается в миллисекундах
Документация Meta, ClickID and the fbp and fbc Parameters.

Если Meta отнесла ваш сайт к категории вроде «Здоровье и благополучие» (с нутрой это частая история), она может урезать параметры URL и пользовательские данные, а часть событий нижней воронки заблокировать. Подробности в справке Meta о категориях источников данных. Скрипт отправляет только стандартные события, сумму и валюту, без названий товаров.

Шаг 1. ID пикселя и токен Conversions API

В Events Manager откройте пиксель, затем «Настройки». В блоке Conversions API, в разделе ручной настройки, нажмите «Создать маркер доступа» (Generate access token). Ссылка видна пользователям с правами разработчика в бизнес-портфолио. ID пикселя написан там же, вверху страницы настроек.

Токен даёт право отправлять события в пиксель, поэтому храните его как пароль: не вставляйте в постбэки, ссылки и код лендинга. В нашем скрипте токены лежат в файле config.php на сервере, а в постбэке передаётся только ID пикселя.

Шаг 2. Параметры кампании в Keitaro

Скрипту нужны ID пикселя, fbclid клика и адрес страницы. Специальных макросов для fbclid и пикселя у S2S-постбэков Keitaro нет, поэтому их записывают в свободные поля кампании. Откройте кампанию, вкладку «Параметры», и задайте:

  • sub_id_10: параметр pixel. В ссылке объявления допишите pixel=ID_ПИКСЕЛЯ, или впишите ID в колонку «Токен или значение», если у кампании один пиксель.
  • sub_id_11: параметр fbclid. Meta сама дописывает fbclid к ссылке при клике, в объявлении его писать не нужно. Если кампания создана по шаблону Facebook и fbclid там уже записан в другой sub_id, используйте его.
  • sub_id_12: в колонке «Токен или значение» адрес лендинга или страницы «спасибо». Без него Meta не примет событие сайта.

Номера sub_id можно взять любые свободные, главное указать те же в адресе постбэка. Ссылка объявления в Facebook с такими параметрами выглядит так:

https://trk.site.com/AbCd12?pixel=123456789012345&utm_source=facebook&utm_campaign={{campaign.id}}&utm_content={{ad.id}}

Как устроены метки и макросы Meta, мы подробно разбирали в статье про UTM-метки.

Шаг 3. Пиксель на лендинге с ID события

Пиксель на странице «спасибо» отправляет Lead с тем же ID, что потом придёт с сервера. В коде локальных лендингов Keitaro подставляет значения вместо макросов {subid} и {sub_id_10}, поэтому код пикселя выглядит так:

<script>
!function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;
n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window,
document,'script','https://connect.facebook.net/en_US/fbevents.js');

fbq('init', '{sub_id_10}', { external_id: '{subid}' });
fbq('track', 'PageView');

// Lead один раз на клик: повторное открытие страницы не даст второе событие.
var leadKey = 'fb_lead_{subid}';
try {
  if (!localStorage.getItem(leadKey)) {
    fbq('track', 'Lead', {}, { eventID: '{subid}' });
    localStorage.setItem(leadKey, '1');
  }
} catch (e) {
  fbq('track', 'Lead', {}, { eventID: '{subid}' });
}
</script>

Главное здесь eventID. По правилам дедупликации Meta склеивает браузерное и серверное событие, если у них совпали event_name и event_id, и отбрасывает дубль, пришедший в течение 48 часов после первого. В скрипте event_id тоже равен subid. external_id пиксель хеширует сам, скрипт отправляет хеш того же subid, так что они совпадут.

Документация Meta: eventID пикселя должен совпадать с event_id сервера, дубли в течение 48 часов отбрасываются
Документация Meta, Handling Duplicate Pixel and Conversions API Events.

Два одинаковых события из браузера Meta между собой не склеивает, поэтому в коде стоит защита от повторной отправки при обновлении страницы.

Шаг 4. Установка скрипта

Скрипту нужен PHP 7.4 или новее с расширениями curl и mbstring. Без mbstring локальная проверка вернёт HTTP 500 до обработки события: ASCII-fallback не заменяет Unicode-нормализацию. Подойдёт папка локального лендинга в Keitaro или любой ваш сервер с HTTPS.

  1. Скачайте архив в конце статьи и залейте папку capi на сервер.
  2. Скопируйте config.sample.php в config.php и заполните ключ постбэка, пиксели с токенами и пароль журнала.
  3. Разрешите PHP запись в папку: там появится журнал logs.

Главное в config.php выглядит так:

return [
	'postback_key' => 'e3b9c1f04a7d2c6b8f15a0d93e7c4b21',
	'log_password' => 'длинный-пароль-для-журнала',
	'pixels' => [
		'123456789012345' => 'EAAB...',
		'234567890123456' => 'EAAG...',
	],
	'events' => [ 'lead' => 'Lead', 'sale' => 'Purchase' ],
	'currency' => 'USD',
	'graph_version' => 'v25.0',
	'test_event_code' => '',
	'default_url' => '',
];

Ключ постбэка нужен, чтобы события в ваш пиксель мог отправить только Keitaro. ID пикселя виден в коде любого лендинга, и без ключа кто угодно мог бы слать через скрипт фальшивые конверсии с вашим токеном. Случайный ключ даёт команда php -r "echo bin2hex(random_bytes(16));".

В примере закреплена Graph API v25.0. Перед рабочим запуском проверьте поддержку выбранной версии и требования Conversions API по журнале изменений Graph API.

Шаг 5. S2S-постбэк в Keitaro

В кампании откройте вкладку S2S-постбэков, нажмите «Добавить», выберите метод GET и статусы lead и sale. Адрес постбэка, одной строкой:

https://trk.site.com/lander/capi/postback.php?key=КЛЮЧ&status={status}&subid={subid}&pixel={sub_id_10}&fbclid={sub_id_11}&url={sub_id_12}&click_time={date:U}&time={conversion_time:U}&ip={ip}&ua={user_agent}&payout={conversion_revenue}&country={country}&city={city}

Все макросы есть в списке макросов S2S-постбэка. {date:U} отдаёт время клика в секундах Unix, {conversion_time:U} время конверсии, {conversion_revenue} доход по этой конверсии. Значения Keitaro кодирует для URL сам.

Документация Keitaro: макросы S2S-постбэка country, user_agent, conversion_revenue и conversion_time
Документация Keitaro, «S2S postback макросы».

Статус lead скрипт отправит как Lead, sale как Purchase с выплатой. Остальные статусы, например rejected, он пропустит. Если у вас ещё работают постбэки от первой версии с параметрами action, clickid, user_agent, revenue и domain, скрипт их поймёт: достаточно добавить к адресу key и поменять путь.

Для Purchase параметр payout должен содержать явное конечное число не меньше нуля: payout=0 сохраняется как value=0. Пустая, нечисловая, отрицательная или бесконечная выплата возвращает локальный HTTP 422, без отправки события. Валюта берётся из currency или настройки по умолчанию и проверяется на формат трёх латинских букв; регистр нормализуется. Это проверка формата, а не полного актуального справочника валют Meta.

Телефон и почту можно добавить в постбэк, если их присылает партнёрская сеть. Входящий постбэк сети умеет обновлять sub_id_1…sub_id_30 клика и конверсии: попросите менеджера передавать телефон в свободный sub_id и добавьте в адрес &phone={sub_id_13}. Скрипт примет телефон открытым или готовым SHA-256.

Шаг 6. Проверка через тестовые события

В Events Manager откройте пиксель, вкладку «Тестовые события», раздел серверных событий, и скопируйте код вида TEST12345. Впишите его в config.php в test_event_code или добавьте к одному постбэку параметр test=TEST12345. Сделайте тестовую конверсию: событие появится во вкладке тестов.

Учтите: события с тестовым кодом Meta не отбрасывает, они учитываются как обычные. После проверки уберите test_event_code из config.php.

Журнал скрипта открывается по адресу …/capi/log.php после ввода пароля в форме. В нём видно каждое событие, ответ Meta и fbtrace_id для обращения в поддержку. Телефоны и почта в журнал не пишутся, только отметка, что они были.

Журнал скрипта log.php: принятые события Lead и Purchase, отказ по конверсии старше 7 дней и ошибка 190 неверного токена
Стенд boostclicks.tech с подставным Graph API.

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

ОтветПричинаЧто делать
Неверный ключ постбэка (403)нет key или он не совпадает с config.phpсверить ключ в адресе постбэка
Для пикселя нет токена (400)ID пикселя не записан в config.php или в sub_id пустодобавить пиксель, проверить параметр кампании
Нет user_agent (422)в постбэке не подставился {user_agent}проверить адрес постбэка
Нет url страницы (422)sub_id с адресом пуст, default_url не заданвписать адрес в параметры кампании
Старше 7 дней (422)сеть подтвердила лид позже, чем через неделютакие события сайта Meta не принимает
Ошибка 190 Invalid OAuth access tokenтокен неверный, отозван или от другого пикселясоздать новый токен для этого пикселя
Конверсии считаются дваждыeventID пикселя и event_id сервера разныев обоих местах использовать subid
Таблица прокручивается вбок

Ошибку 190 мы получили от настоящего Graph API v25.0, отправив событие с заведомо неверным токеном: скрипт показывает её в журнале как есть. Если хотя бы одно событие в запросе старше 7 дней, Meta отклоняет весь запрос, поэтому скрипт отправляет события по одному и старые не отправляет вовсе.

Что было не так в версии 2025 года

Первая версия скрипта лежала в архиве s2s. Мы развернули его на тестовом сервере с тестовым токеном и нашли ошибки, из-за которых его нельзя оставлять в работе.

База с токенами открывалась по ссылке

Токены пикселей, имена и телефоны лидов хранились в файле db/conversions.db внутри папки скрипта. Keitaro работает на nginx, который не читает .htaccess, поэтому файл скачивался по прямому адресу. На стенде мы скачали его целиком вместе с токеном. Пароль от интерфейса по умолчанию был 5555 и передавался прямо в адресе страницы.

Старая версия s2s на стенде: пароль 5555 в конфиге, база conversions.db с токеном скачивается по ссылке, постбэк принят без ключа
Стенд boostclicks.tech, тестовый токен.

Постбэк принимал запросы от кого угодно

У postback.php не было ключа. Зная ID пикселя, любой мог отправить через ваш токен фальшивые конверсии. А имя байера из постбэка выводилось в журнал без экранирования: через подделанный запрос в интерфейс можно было встроить чужой скрипт.

Часть данных не доходила до Meta

IP и User-Agent отправлялись в отдельном блоке context, которого нет в Conversions API: Meta ищет их внутри user_data. События уходили как lead и sale строчными буквами, а стандартные события называются Lead и Purchase. fbc собирался из времени конверсии в секундах вместо времени клика в миллисекундах. Вместо полного адреса страницы передавался домен. Кириллические имена не приводились к строчным перед хешированием, а конверсии старше недели получали время «сейчас».

Имя и телефон в адресе страницы

Инструкция советовала передавать имя и телефон лида на страницу «спасибо» в адресе, а оттуда в трекер тоже через адрес. Так персональные данные оседали в журналах сервера, истории браузера и отчётах. Получение данных от партнёрской сети на сервере не делает открытый GET-постбэк приватным. Проверьте, какие параметры попадают в журналы трекера и веб-сервера, ограничьте доступ и не храните личные данные в query без необходимости.

Что сделать, если вы ставили архив s2s

  1. Удалите папку s2s с сервера целиком, вместе с db/conversions.db.
  2. Считайте токены из неё скомпрометированными: создайте в Events Manager новые и впишите их в config.php новой версии.
  3. Поставьте новую версию и поменяйте адрес постбэка: добавьте key и новый путь.

Скачать скрипт

Архив с новой версией: postback.php, log.php, lib.php, config.sample.php и инструкция README.txt. Первоначальная версия проходила 45 проверок на стенде с подставным Graph API. В патче от 31 октября 2026 исправлены обработка нулевой/невалидной выплаты Purchase и обязательная Unicode-нормализация через mbstring; в архив добавлены tests/run.php и проверка отказа без расширений. Они собирают события локально, без отправки в Meta. Доставку в настоящий API такие тесты не подтверждают. Если нужен трекер, который это всё принимает, сравнение есть в статье про трекеры для арбитража.

Прогон новой версии скрипта на стенде: 45 проверок без провалов
Стенд boostclicks.tech, 01.10.2026.

Частые вопросы

Нужен ли пиксель, если настроен Conversions API?

Да, Meta советует использовать оба. Пиксель передаёт события сразу и с данными браузера, сервер дополняет то, что пиксель потерял, и передаёт продажи, которых на лендинге не видно. Дубли Meta склеит по event_id.

Чем встроенная интеграция Keitaro отличается от скрипта?

Интеграция настраивается без кода, но доступна с тарифа Advanced и отправляет конверсии только по кликам с fbclid. Скрипт работает на любом тарифе, принимает ID пикселя в постбэке, ведёт журнал ответов Meta и отправляет конверсии без fbclid.

Можно ли отправлять в один скрипт конверсии нескольких пикселей?

Да. Впишите все пиксели с их токенами в config.php, а ID пикселя передавайте в постбэке. Один адрес постбэка обслужит всех байеров и все кампании.

Почему конверсия не появилась в Meta?

При HTTP 500 сначала проверьте расширения curl и mbstring. При HTTP 422 проверьте время, User-Agent, адрес страницы, а для Purchase ещё явную выплату не меньше нуля и формат валюты. Остальные ответы и ошибки ищите в log.php; нулевой payout не считается отсутствующим.

Нужно ли хешировать IP и User-Agent?

Нет. IP, User-Agent, fbc и fbp передаются как есть. В SHA-256 переводят телефон, почту, имя, город, страну, а external_id Meta рекомендует хешировать. Скрипт делает это сам.

Можно ли отправить конверсию, которой больше недели?

Нет, события сайта Meta принимает не старше 7 дней, а запрос с таким событием отклоняет целиком. Скрипт не подменяет время на текущее, а пишет такую конверсию в журнал как ошибку.

Редакция BoostClicks

Материалы о настройке рекламы, трекинге и автоматизации: инструкции, примеры кода и расчёты с указанием условий проверки.