Mini Apps: трекайте запуск, не теряя атрибуцию

Если ваша воронка заканчивается не диалогом с ботом и не вступлением в канал, а Mini App, то конверсия - это сам запуск приложения. Происходит он на вашем домене, где наш бот не видит ничего. Короткий сниппет закрывает этот разрыв: читает параметры запуска, которые Telegram и так передал приложению, отправляет их в Leadgram, и запуск попадает в воронку событием miniapp_launch, привязанным к клику, который привёл человека.

Как работает трекинг Mini App

При запуске Telegram отдаёт каждому Mini App подписанную строку initData. В ней пользователь, метка времени и - если приложение открыли по диплинку - start_param. Строка подписана токеном вашего бота, поэтому, получив её, мы можем проверить, что запуск действительно пришёл из Telegram и именно для вашего бота. Подделать запуск, не имея вашего токена, нельзя.

Дальше мы определяем, какому клику принадлежит запуск. Если в start_param лежит click id Leadgram - это и есть атрибуция, ровно как с диплинками /start у ботов. Если нет - берём последний клик этого Telegram-пользователя в вашей организации за последние семь дней. Если не нашлось ни того, ни другого, запуск просто не трекается: атрибуцию мы никогда не угадываем.

Сниппет только ЧИТАЕТ параметры запуска. Он не вызывает методы Telegram.WebApp, а значит переживает origin-защиту, которую Telegram включает с 20 июля 2026 года, - и продолжил бы работать, даже исполняясь на чужом домене. Подробности - в Origin-защите Mini App.

Добавьте сниппет

Вставьте это в свой Mini App - на страницу, которую Telegram загружает первой. Ни библиотек, ни JS-моста Telegram не нужно.

<script>
  (function () {
    // Параметры запуска Telegram кладёт во фрагмент URL. Чтобы их прочитать,
    // мост Telegram.WebApp не нужен - поэтому сниппет переживает origin-защиту.
    var params = new URLSearchParams(window.location.hash.slice(1));
    var initData = params.get("tgWebAppData");
    if (!initData) return;

    fetch("https://leadgram.org/api/miniapp/YOUR_BOT_ID/event", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ initData: initData }),
    }).catch(function () {
      // Трекинг не должен ломать ваше приложение - глушим ошибки.
    });
  })();
</script>

Замените YOUR_BOT_ID на id бота со страницы ботов. Этот id не секрет: он лишь указывает, чьим токеном проверять подпись, а запрос без валидной подписи отклоняется.

Если ваш Mini App - SPA, вызовите сниппет один раз при первой загрузке. Дёргать его на каждой смене роута безвредно (повторные запуски одного человека схлопываются в одно событие), но это лишние запросы.

Передайте click id

Чтобы привязать запуск к конкретному клику, положите click id в диплинк, который открывает Mini App:

https://t.me/YOUR_BOT/YOUR_APP?startapp={click_id}

Telegram доставит {click_id} в приложение как start_param внутри initData, а сниппет передаст его дальше нетронутым. Ваша трекинг-ссылка редиректит на этот URL, так что click id идёт от объявления до приложения сам, без вашего участия в промежутке.

Не указывайте трекинг-ссылку Leadgram в поле Mini App URL в BotFather. Редирект отработает, но ваш Mini App окажется зарегистрирован на домене трекера, а не на вашем, и origin-защита Telegram сломается для всего приложения. Указывайте в BotFather свой настоящий домен, а click id передавайте через startapp.

Что вы увидите

Проверенный запуск появляется на странице Событий как miniapp_launch - с привязкой к приведшему клику и с start_param в payload. Дальше он ведёт себя как любое событие: поднимает ваши постбэки, попадает в отчёты и маппится в ViewContent на стороне Meta - вовлечённый просмотр контента, не лид и не покупка.

Повторные запуски одного человека дедуплицируются: Mini App открывают снова и снова, и каждое открытие - не новая конверсия. Если внутри приложения вы ещё и продаёте за Telegram Stars, такие покупки приходят отдельно - см. События и конверсии.

Когда запуск подлинный, но клика за человеком нет, эндпоинт отвечает 200 и tracked: false. Это не ошибка: интеграция работает, просто конкретно этот пользователь пришёл мимо отслеживаемой кампании.