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. Это не ошибка: интеграция работает, просто конкретно этот пользователь пришёл мимо отслеживаемой кампании.