Перейти до вмісту
Усі статті
7 хв читання

Трекінг deep link у Telegram: два package ID, яких ніхто не чекає

Deep link Telegram розгалужується на три Android-пакети і одне iOS-переписування tg://resolve

Ви передаєте click ID у Telegram-бота через ?start=, а ваш postback повертається порожнім для частини Android-встановлень, які всі одностайно вважають реальним трафіком. Бот залогував команду /start. Просто він так і не отримав ваш payload — або отримав, але з пакета, який ваша звітність ніколи не враховувала. Обидва пояснення дають однаковий симптом: розрив, який виглядає як баг трекінгу, а насправді є прогалиною в маршрутизації.

Три способи передати значення в Telegram

t.me-посилання передають значення в Telegram через три різні параметри, і вони не взаємозамінні:

ПараметрКуди потрапляє значенняЛімітУмова
?start=<payload>передається боту як аргумент команди /startдо 64 символів base64urlвідвідувач має тапнути START
?startapp=<payload>init data Mini App, лише на клієнтідо 512 символівдоходить до вашого сервера, тільки якщо сам Mini App пересилає й валідує значення
?startchannelпростий флагвзагалі без payloadтут нічого прикріпити

?start=: створений саме для цього

Це параметр, який поводиться так, як більшість трекерів очікує від параметра deep link. Він передається боту напряму як аргумент команди /start, тобто логіка вашого бота читає його так само, як будь-який інший аргумент команди — не потрібна окрема обробка init data, не потрібен власний клієнтський код. Обмеження, яке на практиці справді має значення, — ліміт у 64 символи: це base64url, який комфортно вміщує більшість внутрішніх click ID, але достатньо тісний, щоб доповнений нулями або багатослівний ідентифікатор переповнив його раніше, ніж ви помітите. І значення приходить лише тоді, коли відвідувач тапає START — t.me-посилання, яке відкриває чат, але так і не отримує тап, не передає payload нікуди, незалежно від того, що ви поклали в URL.

https://t.me/your_bot?start=dc_9Kx2Qz

доходить до бота як:

/start dc_9Kx2Qz

У цьому циклі нічого не змінюється залежно від платформи чи того, який пакет Telegram обробив тап — payload доходить до бота однаково, чи маршрутизував його Android через Play-збірку, APK з telegram.org, чи Telegram X, і незалежно від того, чи прийшов він через переписування tg://resolve на iOS. Єдина змінна, яка впливає на те, що бачить бот, — сам payload.

?startapp=: зовсім інша тварина

?startapp= виглядає як більша версія ?start= — більше символів дозволено, до 512, — і саме ця схожість і провокує помилку. Він поводиться зовсім по-іншому. Значення передається на клієнті, в init data Mini App, а не в обробник команди бота. Саме по собі це значення не доходить до вашого сервера. Воно доходить до сервера лише тоді, коли код Mini App, яким керує оператор, читає ці init data і пересилає їх, з власною валідацією, туди, де ви збираєте дані. Якщо ви не контролюєте Mini App, або якщо Mini App не побудований так, щоб пересилати значення, payload може лежати прямо в клієнті й жодного разу не торкнутися бекенду, до якого у вас є доступ.

?startchannel: нічого нести

?startchannel — це простий флаг. Він взагалі не приймає значення. Якщо план полягав у тому, щоб передати click ID у deep link каналу так само, як ?start= передає його боту, тут немає механізму для цього — параметр просто не побудований для того, щоб тримати payload, і те, що ви до нього додасте, нічого не змінить.

Що відбувається на iOS: переписування tg://resolve

На iOS t.me-посилання не потребує, щоб ви вручну будували URL із власною схемою. Підтверджено, що працюють два переписування:

https://t.me/<bot>?start=<payload>  ->  tg://resolve?domain=<bot>&start=<payload>
https://t.me/<channel>              ->  tg://resolve?domain=<channel>

Випадок з ботом — той, що має значення для трекінгу: payload start виживає при переписуванні цілим, переноситься як власний параметр у URL tg://resolve, а не губиться чи перекодовується по дорозі. Якщо ваше посилання t.me/<bot>?start=<payload> працює на Android, той самий payload доходить до того самого бота на iOS без жодної додаткової обробки з вашого боку. Випадок з каналом переписується так само, тільки без payload start — канали не боти, тож немає нічого еквівалентного, що можна було б нести.

Пастка Android-пакетів: три ID, один прихований на видноті

Саме тут більшість налаштувань тихо втрачають трафік без жодної помилки, яка б це показала. Telegram на Android — це не один пакет, а три:

ДжерелоПакет
Play Store-збіркаorg.telegram.messenger
APK, який Telegram роздає зі свого сайтуorg.telegram.messenger.web
Telegram Xorg.thunderdog.challegram

Більшість налаштувань маршрутизації орієнтуються лише на org.telegram.messenger, бо саме він вважається «тим самим» Telegram у Play Store. Але APK, який Telegram роздає безпосередньо з telegram.org — зовсім не через Play, — має зовсім інший package ID. Прочитано прямо з маніфесту цього APK: package=org.telegram.messenger.web, versionName 12.10.0. Будь-хто, хто встановив Telegram із власного сайту Telegram, а не з Play Store, працює саме з цим пакетом — і жодна маршрутизація за пакетами, яка називає лише org.telegram.messenger, ніколи його не побачить.

Це не похибка округлення у ваших Android-цифрах. Це відвідувач, на пристрої якого справді встановлено Telegram, коректно, з джерела, яким керує сам Telegram, — і який невидимий для ланцюжка, побудованого на один package ID.

Telegram X, org.thunderdog.challegram, — третій окремий клієнт понад це. Це окремий застосунок з окремого дистрибутиву, і його варто включати в той самий ланцюжок пакетів, якщо реальна частка вашої аудиторії справді ним користується.

Чому це виглядає як баг трекінгу, а не прогалина в маршрутизації

Пропущений пакет не породжує жодної помилки в жодній точці ланцюжка. Відвідувач тапає ваше посилання, Android передає його тому пакету Telegram, який встановлено, той застосунок відкривається, бот отримує /start з payload, прикріпленим точно так, як задумано, і логіка вашого бота спрацьовує. З боку Telegram усе спрацювало. Прогалина існує лише на вашому боці, у припущенні, закладеному в логіку маршрутизації чи звітності, яка від самого початку вирішила, з яких пакетів очікувати трафік.

Саме тому org.telegram.messenger.web так легко пропустити на місяці: це не зламане встановлення, не помилка в налаштуванні бота і не payload, що не дійшов. Це трафік, який ніколи не рахувався окремим джерелом, бо ніхто не зафіксував, що Telegram випускає другий Android-пакет поза Play. Аргумент /start, ліміт у 64 символи, переписування на iOS — жодна з цих поведінок не відрізняється для цього пакета порівняно з Play-збіркою. Єдине, що відрізняється, — чи знає ваш власний список пакетів, що це джерело взагалі існує.

Що насправді доходить до вашого postback

Складіть три нитки разом, і картина буде послідовною: для трекінгу на основі /start ваш ідентифікатор виживає при передачі аргументу боту, виживає при переписуванні схеми на iOS цілим, а далі повністю залежить від того, які саме Android-пакети називає ваша маршрутизація. Пропустіть org.telegram.messenger.web — і ви не просто не відстежуєте рідкісний крайній випадок, ви не відстежуєте кожного відвідувача, який довірився власній сторінці завантаження Telegram більше, ніж Play Store. Для Mini Apps ?startapp= доходить до сервера взагалі лише тоді, коли пересилання робить ваш власний код Mini App; ніщо зовнішнє щодо цього Mini App саме по собі значення не побачить.

Трекеру, який генерує t.me-посилання для кампанії, потрібен список пакетів, що включає org.telegram.messenger.web поряд з Play-збіркою, не тому що це екзотичний крайній випадок, а тому що це той самий застосунок, виданий через інші двері. Telegram-роутинг DarkCore за замовчуванням несе всі три Android-пакети саме з цієї причини: розподіл трафіку між ними — не шум, який можна усереднити, а реальна популяція встановлень, про яку ланцюжок з одним пакетом просто ніколи не питає.

Що перевірити, перш ніж довіряти цифрам

Більшість цього непомітна, доки ви цілеспрямовано не почнете шукати, бо жодна з проблем не викликає помилку на боці Telegram. Короткий чекліст перед запуском кампанії ловить майже все:

  • Переконайтеся, що ваш click ID уміщується в 64 символи base64url, перш ніж він потрапить у ?start= — усе довше або обрізається, або відхиляється, залежно від того, де застосовано ліміт, і жоден із цих результатів не хочеться виявити вже в продакшні.
  • Не маршрутизуйте payload ?startapp=, вважаючи, що він автоматично з’явиться на сервері. Це станеться, лише якщо контрольований вами Mini App явно його пересилає.
  • Якщо мета — донести payload у deep link каналу, не покладайтеся на ?startchannel — це флаг, а не контейнер, і жодне значення, яке ви до нього додасте, нікуди не потрапить.
  • Додайте org.telegram.messenger.web до будь-якого Android-ланцюжка пакетів, побудованого для Telegram. Пропуск цього пакета не зменшує ваш трафік — він просто не дає вам побачити частину, яка завжди там була.
  • Якщо Telegram X має реальну частку серед ваших відвідувачів, включіть org.thunderdog.challegram у той самий ланцюжок, а не розглядайте його як окремий, другорядний випадок.
  • telegram start parameter
  • t.me deep link
  • трекінг telegram bot
  • tg resolve scheme
  • org.telegram.messenger