Mini Apps: track the launch, keep the attribution
If your funnel ends in a Mini App rather than a bot conversation or a channel join, the launch itself is the conversion you care about - and it happens on your domain, where our bot sees nothing. A short snippet closes that gap: it reads the launch parameters Telegram already handed your app, posts them to Leadgram, and the launch lands in your funnel as a miniapp_launch event, attributed to the click that brought the person in.
How Mini App tracking works
Telegram hands every Mini App a signed initData string at launch. It carries the user, a timestamp and - when the app was opened through a deep link - a start_param. That string is signed with your bot's token, so when you forward it to us we can verify it really came from Telegram for your bot. Nobody can forge a launch without your token.
We then resolve which click the launch belongs to. If start_param carries a Leadgram click id, that's the attribution, exactly as /start deep links work for bots. If it doesn't, we fall back to the last click we saw for this Telegram user in your organization, within a seven-day window. If neither finds anything, the launch is simply not tracked - we never guess an attribution.
The snippet only READS launch parameters. It never calls Telegram.WebApp methods, which means it keeps working under the origin protection Telegram switches on from 20 July 2026 - and it would keep working even if it ran on a different domain. See Mini App origin lockdown.
Add the snippet
Paste this into your Mini App, on the page Telegram loads first. It needs no libraries and no Telegram JS bridge.
<script>
(function () {
// Launch params come from the URL fragment Telegram appends. Reading them
// needs no Telegram.WebApp bridge, so this survives origin restrictions.
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 () {
// Tracking must never break your app - swallow failures.
});
})();
</script>
Replace YOUR_BOT_ID with the bot id from your bots page. That id is not a secret - it identifies which bot's token we verify the signature against, and a request without a valid signature is rejected.
If your Mini App is a single-page app, run this once on first load. Firing it on every route change is harmless - repeat launches by the same person collapse into one event - but it's wasted requests.
Pass the click id
To attribute a launch to a specific click, put the click id in the deep link that opens your Mini App:
https://t.me/YOUR_BOT/YOUR_APP?startapp={click_id}
Telegram delivers {click_id} to your app as start_param inside initData, and the snippet forwards it untouched. Your tracking link redirects to this URL, so the click id flows from ad to app without you handling it anywhere in between.
Don't put a Leadgram tracking link in the Mini App URL field in BotFather. The redirect works, but your Mini App ends up registered on the tracker's domain instead of yours, which breaks Telegram's origin protection for your whole app. Point BotFather at your real domain and pass the click id through startapp instead.
What you'll see
A verified launch appears on the Events page as miniapp_launch, tied to the click that brought the user in, with the start_param in the payload. From there it behaves like any other event: it fires your postbacks, it counts toward reports, and it maps to ViewContent on Meta - an engaged content view, not a lead and not a purchase.
Repeat launches by the same person are deduplicated: a Mini App gets opened over and over, and each open is not a new conversion. If you also sell through Telegram Stars inside the app, those purchases arrive separately - see Events and conversions.
The endpoint answers 200 with tracked: false when a launch is genuine but the person has no click behind them. That is not an error - it means your integration works and this particular user simply arrived outside a tracked campaign.