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. Це не помилка: інтеграція працює, просто конкретно цей користувач прийшов повз відстежувану кампанію.