Перейти к содержимому
LinkProfit

Отслеживание конверсий по коротким ссылкам: идентификаторы клика, окна и серверные события

LinkProfit Team10 мин чтения
  • conversions
  • analytics
  • attribution
  • link-shortener
На этой странице

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

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

Клик — это расход, а не результат

Отчётность, которая заканчивается кликами, живёт потому, что клики — простое измерение. Редирект происходит на инфраструктуре, которой управляете вы, поэтому его подсчёт не требует ничьего согласия, тогда как всё, что дальше, происходит в другом месте. Наш гид о том, как на самом деле отслеживаются клики по ссылкам, разбирает, что вообще может содержать событие одного клика; коротко — оно знает, что клик был, и ничего не знает о том, что было потом.

У этого ограничения есть вполне реальные последствия. Два размещения могут давать одинаковый объём кликов, при том что одно приводит покупателей, а второе — людей, уходящих через три секунды. Разбивка по странам, выглядящая внушительно на кликах, на выручке может перевернуться. Split-тесты, решённые по доле переходов, регулярно выбирают вариант с более агрессивным заголовком и худшим доведением до оплаты. Пока к тем же измерениям не привязана выручка, каждое такое суждение — догадка, переодетая в метрику.

Чтобы её привязать, нужно ровно одно: значение, которое переживёт путь от редиректа до заказа.

Идентификатор — это и есть вся конструкция

На каждом редиректе воркер выдаёт токен и делает с ним две вещи. Он добавляет токен к адресу назначения под тем именем параметра, которое выбираете вы, — по умолчанию lp_cid, — и пишет то же самое значение в cookie вашего домена редиректов, действующую 90 дней.

Копий две, потому что потеряться может любая. Адреса назначения вырезают параметры запроса — иногда намеренно, ради опрятных URL, иногда как побочный эффект собственного редиректа. А посетитель, который кликнул сегодня и вернулся через три дня, набрав адрес руками, никакого параметра уже не несёт, зато несёт cookie. По отдельности ни одна копия не надёжна; вместе они покрывают большинство реалистичных путей к покупке.

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

Что везёт токен

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

Содержимое токена намеренно узкое: момент клика, ссылка, вариант split-теста, страна, класс устройства, источник трафика и признак подозрительного трафика. Никаких персональных данных. Этот же список и делает колонку выручки полезной: каждое из полей превращается в измерение, по которому выручку можно разложить в аналитике, не связывая ничего ни с чем во второй раз.

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

Окно атрибуции — решение бизнеса

Окно — это предельный возраст клика, которому ещё можно засчитать конверсию. Это настройка каждого рабочего пространства и единственное число здесь, о котором стоит спорить, а не принимать его как значение по умолчанию.

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

Сценарий отказа, которого эта конструкция избегает, — молчаливое отклонение. Конверсия, пришедшая позже окна, отвергается кодом attribution_expired, отличным от invalid_click_id. Эти два состояния лечатся совершенно по-разному, и интеграция, получающая на оба один общий код ошибки, потратит неделю на отладку не того. Логируйте код, считайте оба случая отдельно и относитесь к растущей доле attribution_expired как к признаку того, что окно больше не соответствует вашему циклу продаж.

У двух путей приёма разные потолки. Cookie живёт 90 дней, поэтому браузерный отчёт, который на неё опирается, дольше не проживёт. Серверный отчёт хранит сам идентификатор и ограничен только окном рабочего пространства.

Два входа, один свод правил

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

Серверное событие

Ваш бэкенд отправляет идентификатор вместе с целью, идентификатором заказа, суммой и валютой.

curl -X POST https://api.linkprofit.com/v1/conversions \
  -H "Authorization: Bearer lp_live_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-10241" \
  -d '{
    "click_id": "1.eyJ1aWQiOiJ...",
    "goal": "purchase",
    "order_id": "10241",
    "amount_cents": 4999,
    "currency": "usd"
  }'

Ключу нужна область conversions:write, а значит, этот путь стоит вам того, чего не стоит браузерный: учётные данные, которые надо выпустить, хранить и ротировать. Как устроены ключи с областями действия, описано в разделе аутентификация API; держите этот ключ на сервере — ключу с правом записи в ваши данные о выручке не место на странице.

Взамен вы получаете отчёт, который не подавит ни блокировщик рекламы, ни блокировщик скриптов, ни настройка защиты от отслеживания, ни ошибка JavaScript. Он срабатывает с вашей собственной инфраструктуры в тот момент, когда ваша же система соглашается, что заказ существует, и потому отражает правду после проверок на мошенничество, а не оптимистичный момент нажатия кнопки.

Браузерное событие

Воркер отдаёт небольшой скрипт с вашего собственного домена редиректов, а страница благодарности его вызывает.

<script src="https://go.example.com/cv.js" defer></script>
<script>
  window.lpConversion({ goal: 'purchase', orderId: '10241', amountCents: 4999, currency: 'usd' });
</script>

Скрипт читает идентификатор из URL или из cookie вашего домена, поэтому вручную ему ничего передавать не нужно. Стороннего хоста в цепочке нет нигде, и это важно дважды: это свойство приватности и свойство white-label, потому что страница вашего клиента не загружает ничего, что называло бы платформу под ней.

Цена здесь обычная для клиентского измерения. Блокировщики, режимы приватности, не загрузившийся скрипт и посетитель, закрывший вкладку на полсекунды раньше, — всё это убирает события, и убирает неравномерно. Техническая и внимательная к приватности аудитория подавляет их куда сильнее, чем потребительская, поэтому схема только на браузере не просто недосчитывает — она недосчитывает неравномерно по сегментам.

Как выбрать между ними

Используйте серверный путь везде, где о заказе знает сервер, — то есть почти везде, где переходят деньги. Браузерный путь берите для результатов, которые существуют только в браузере, или там, где серверный код добавить нельзя: страница, которую вы правите лишь через менеджер тегов, регистрация на чужой хостинговой платформе, посадочная страница клиента, которая вам не принадлежит.

Держать оба пути для одного результата безопасно благодаря дедупликации — но только если оба отправляют один и тот же order_id. Без этого вы не добавляете покрытие, а удваиваете выручку.

Сами цели устроены легко. Цель — это именованный результат вроде purchase, signup или trial; она может нести значение и валюту по умолчанию для конверсий, приходящих без суммы, а цель, упомянутая до того, как она заведена, создаётся при первом использовании.

Деньги — целое число

Суммы — целые минимальные единицы. 4999 означает 49.99 в валюте с двумя знаками после запятой, а сумма 49.99 отклоняется с указанием на поле, а не округляется молча.

Это раздражает примерно день, а выручает потом годами. Двоичная плавающая точка не умеет точно представить большинство десятичных дробей, поэтому классическая демонстрация, где сложение двух сумм даёт третью с неожиданной цифрой в хвосте, — не курьёз, а то, что происходит с каждой суммой в колонке выручки на объёме. А валюты без дробной части ломают любое допущение, будто делить на сто всегда правильно.

Отказ принимать дробь на границе выталкивает единственное честное преобразование — из человеческой цены в минимальные единицы — ровно в одно место: в ваш код, один раз, туда, где его можно покрыть тестом.

Дубликаты — забота базы данных

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

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

Практическое правило: выберите идентификатор заказа, устойчивый и уникальный в вашей системе, и больше никогда не меняйте способ, которым вы его получаете. Ваш собственный номер заказа обычно подходит; отметка времени или что угодно, пересоздаваемое при повторе, подходит ровно наоборот. Добавьте к нему заголовок Idempotency-Key, как в запросе выше, — и упавший вызов превращается в то, что повторяют, а не расследуют.

Подозрительный трафик помечается, а не прячется. Вердикт классификатора едет внутри токена, поэтому конверсия, привязанная к дата-центру или прокси, помечается подозрительной в момент записи и появляется в отчётах отдельным сегментом. «Двести конверсий» и «двести конверсий, сорок из них из одного хостингового диапазона за час» — разные факты, и платить стоит только за один. Ровно здесь данные о конверсиях и фильтрация трафика перестают быть отдельными функциями.

Когда конверсия происходит в другом месте

Основная сложность на практике не в API. Она в том, что момент, который стоит измерить, происходит внутри хостингового магазина, CRM или биллингового провайдера, а ваша задача — довезти одну строку от клика в эту систему и обратно.

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

CRM и сделки с участием продавца. Заберите идентификатор скрытым полем на форме заявки и сохраните его на записи, а конверсию отправьте, когда сделка помечена выигранной. Ловушка здесь во времени: сделке, закрывающейся за семь недель, нужно окно, вмещающее семь недель, а если единственное место, где известен идентификатор, — ваша CRM, то её сроки хранения и возможности выгрузки становятся частью вашей архитектуры атрибуции. Подумайте о том, чтобы отправлять цель signup при захвате заявки и цель purchase при закрытии, — тогда верх воронки измеряется, даже когда низ занимает квартал.

Биллинг и подписки. Пусть триггером будет webhook биллингового провайдера. Когда счёт оплачен, ваш сервер находит идентификатор, сохранённый для этого клиента, и отправляет конверсию, где идентификатором заказа служит номер счёта. Регулярные списания тогда естественно приходят отдельными конверсиями, а первые платежи остаются отличимыми от продлений через цель.

Во всех трёх случаях схема одна и та же: внешней системе не нужно знать о ссылках ничего. Она держит одну непрозрачную строку и возвращает её вам.

Куда цифры уходят дальше — сознательно традиционно. Подписанное событие conversion.created отправляется через обычную механику webhook, а настроенные рекламные интеграции получают конверсию через очередь доставки с описанным правилом пауз и отметкой об отказе вместо бесконечных повторов. Тариф может ещё и ограничивать число принятых конверсий за календарный месяц, считая его в UTC, и превышение этого лимита отвечает кодом quota_exceeded, а не ограничением тарифа, — поэтому «не входит в ваш тариф» и «израсходовано в этом месяце» различимы без обращения в поддержку.

Как сделать правильно с первого раза

  1. Включайте конверсии до кампании, а не после. Идентификаторы выдаются в момент редиректа и не создаются задним числом.
  2. Ведите ссылки на собственном домене, чтобы cookie принадлежала вам.
  3. Задавайте окно по измеренному циклу покупки и пересматривайте его, когда доля attribution_expired меняется.
  4. Предпочитайте серверный путь везде, где о заказе знает сервер.
  5. Переводите цены в целые минимальные единицы ровно в одном месте вашего кода.
  6. Используйте настоящий номер заказа как идентификатор заказа и отправляйте его одинаково из каждого пути.
  7. Логируйте коды отклонений раздельно, раз в период сверяйтесь с биллингом и разбирайтесь с расхождением, а не усредняйте его.

Полный справочник полей лежит в документации по конверсиям, а страница функции отслеживания конверсий описывает, как колонка выручки ведёт себя в тех отчётах, которые вы и так читаете. Ничто из этого не заменяет бухгалтерию. Оно отвечает на более узкий вопрос, на который бухгалтерия ответить не может: какая ссылка, какая страна, какой адрес назначения и какой источник трафика принесли деньги.

О чём обычно спрашивают

Что такое идентификатор клика и где он хранится?

Это подписанный токен, который редиректор выдаёт в момент редиректа. Он добавляется к адресу назначения под тем именем параметра, которое выбираете вы, — по умолчанию lp_cid, — и то же самое значение пишется в cookie вашего собственного домена редиректов со сроком жизни 90 дней. Копий две, потому что потеряться может любая: адрес назначения, вырезающий параметры запроса, оставляет cookie, а посетитель, вернувшийся через несколько дней уже без параметров, всё ещё несёт её с собой. Токен подписан и привязан к рабочему пространству и партнёру, для которых он был выдан, поэтому токен со ссылки одного клиента отвергается в пространстве другого ровно как подделка.

Работает ли отслеживание конверсий без сторонних cookie?

Да, потому что в этой цепочке нет ничего стороннего. Идентификатор едет в адресе назначения, а резервная cookie ставится вашим собственным доменом редиректов, а не хостом платформы. Браузерный скрипт, который сообщает о конверсиях со страницы благодарности, отдаётся с того же вашего домена, поэтому страница не загружает ничего принадлежащего другой компании. Браузеры убирают ровно один механизм — cookie, поставленную хостом, на который посетитель никогда не переходил; здесь он не используется.

Почему суммы передаются целыми центами, а не дробными числами?

Потому что правило округления, придуманное посреди платёжного пути, — это и есть то, из-за чего отчёты по выручке тихо перестают сходиться со счетами. Суммы — целые минимальные единицы: центы, пенсы, копейки. Сумма 49.99 отклоняется с указанием на поле, а не округляется молча до чего-то правдоподобного. Арифметика с плавающей точкой не умеет точно представить большинство десятичных дробей, поэтому сумма тысяч таких значений уплывает, и уплывает незаметно — пока финансисты не спросят, почему панель и учётная книга расходятся на несколько сотен единиц.

Что будет, если моя система отправит один и тот же заказ дважды?

Запишется одна конверсия, а второй вызов вернёт её же с пометкой о дубликате. Дедупликация — это одна атомарная вставка, а не чтение с последующей записью, поэтому она держится, даже когда две доставки приходят в один и тот же момент от повторённого webhook. Именно это делает повтор безопасным: интеграция, которая не знает, прошёл ли её предыдущий вызов, должна просто отправить запрос ещё раз с тем же идентификатором заказа.

Как выбрать окно атрибуции?

Измерив, сколько на самом деле длится ваш цикл покупки, а не скопировав число из рекламной платформы. Посмотрите на разрыв между первым касанием и покупкой у реальных заказов: импульсная покупка закрывается за минуты, обдуманная — за неделю, корпоративная сделка — за квартал. Окно короче вашего настоящего цикла выбрасывает заработанную вами выручку; окно намного длиннее приписывает ссылкам покупки, к которым они не имели отношения. Конверсия, пришедшая после окна, отклоняется кодом attribution_expired, отличным от invalid_click_id, поэтому ваша интеграция отличает «слишком поздно» от «сломанного идентификатора», а не гадает.

Можно ли привязать конверсию, которая происходит в магазине или CRM, которыми я не управляю?

Обычно да — при условии, что система позволяет сохранить на заказе или на записи одну дополнительную строку. Заберите идентификатор из адреса или из cookie вашего домена, когда посетитель приходит, положите его в скрытое поле формы или в произвольный атрибут заказа и отправьте обратно со своего сервера, когда заказ подтверждён. Если платформа не даёт никаких произвольных полей, но разрешает скрипт на странице подтверждения, вместо этого работает браузерный путь. Единственный случай без красивого ответа — система, которая не принимает ни произвольных данных, ни скриптов; честные варианты там — переделанное оформление заказа или отдельные посадочные страницы под каждую ссылку.