Вбудована аналітика Telegram
Telegram надає інструменти для аналізу результатів рекламних розміщень за допомогою унікальних посилань. Ви можете створювати окреме посилання для кожного рекламного розміщення. Для каналів і груп статистика вступів доступна безпосередньо в Telegram, а для ботів і Mini Apps необхідно додатково налаштувати збереження параметрів посилань і збір даних на боці проєкту.
УВАГА
Одне рекламне розміщення — одне унікальне посилання. Якщо використовувати одне посилання в кількох оголошеннях, джерела трафіку змішаються, і розділити їх заднім числом не вийде.
Цей спосіб аналітики працює окремо від статистики кампаній і відстеження конверсій AdsGram.
Частина 1. Для менеджерів кампаній на боці рекламодавця
1. Створюйте окреме посилання для кожного рекламного розміщення
Щоб порівнювати результати різних рекламних розміщень, використовуйте унікальне посилання для кожного з них.
Наприклад, якщо ви просуваєте проєкт у трьох Telegram-каналах, створіть три окремі посилання. Це дозволить визначити, які розміщення залучають більше користувачів.
Тип посилання залежить від того, куди веде реклама:
| Куди веде реклама | Формат посилання | Де відстежувати результат |
|---|---|---|
| Telegram-канал або група | Окреме запрошувальне посилання | Telegram: налаштування каналу або групи → Invite links |
| Бот | t.me/YourBot?start=ad_sep_anna | Ваш бот, якщо він зберігає параметр |
| Mini App | t.me/YourBot?startapp=ad_sep_anna | Сервер вашого застосунку, якщо він зберігає параметр |
Замініть YourBot на ім'я свого бота, а ad_sep_anna — на унікальний параметр рекламного розміщення.
2. Канали та групи: запрошувальні посилання
Створюйте окреме запрошувальне посилання для кожного рекламного розміщення.
- Відкрийте канал або групу та натисніть на її назву.
- Перейдіть до налаштувань редагування. У десктопній версії відкрийте меню ⋮ →
Manage channel/Manage group. - Відкрийте розділ
Invite linksі виберіть створення нового посилання. - Вкажіть назву, що відповідає розміщенню, наприклад
ad_sep_anna. Назву бачать лише адміністратори, а не користувачі, які переходять за посиланням. - За потреби задайте термін дії посилання, обмеження за кількістю користувачів або необхідність схвалення заявки на вступ адміністратором.
- Використовуйте посилання лише в одному рекламному розміщенні.
Де дивитися статистику: у розділі Invite links Telegram показує кількість користувачів, які вступили за кожним посиланням. Відкривши конкретне посилання, можна переглянути список користувачів.
Звичайне публічне посилання на кшталт t.me/yourchannel не дозволяє розділити вступи за рекламними розміщеннями. Публічні канали теж можуть створювати запрошувальні посилання — використовуйте окремі посилання в рекламі.
3. Боти: посилання з параметром start
Використовуйте посилання такого формату:
https://t.me/<bot>?start=<parameter>Наприклад:
https://t.me/YourBot?start=ad_sep_annaКоли користувач переходить за посиланням і натискає Start, бот отримує команду з параметром:
/start ad_sep_annaTelegram не веде автоматичну статистику таких переходів і запусків за рекламними параметрами. Бот має самостійно зберігати параметр під час першого створення запису користувача.
Враховуйте лише нових користувачів, якщо ваша метрика — залучення нових користувачів. Якщо наявний користувач відкриває рекламне посилання, це не робить його новим користувачем.
4. Mini Apps: посилання з параметром startapp
Для основного Mini App бота використовуйте посилання:
https://t.me/<bot>?startapp=<parameter>Для Mini App, створеного через /newapp у @BotFather, можна використовувати формат:
https://t.me/<bot>/<app>?startapp=<parameter>Наприклад:
https://t.me/YourBot?startapp=ad_sep_annaЗа потреби можна додати параметр режиму відображення:
&mode=compact— компактний режим.&mode=fullscreen— повноекранний режим.
Mini App отримує переданий параметр у полі start_param. Сервер застосунку має зберегти його під час першого запуску користувача.
Якщо користувач відкрив Mini App без рекламного посилання — наприклад, через кнопку меню або профіль бота, — рекламного параметра може не бути. Такий запуск слід вважати органічним, якщо немає іншого надійного джерела атрибуції.
5. Правила для параметрів
Максимальна довжина:
- Параметр
start— 64 символи - Параметр
startapp— 512 символів
- Параметр
Допустимі символи:
A-Z,a-z,0-9,_,-- Не використовуйте пробіли, кирилицю та крапки. Щоб уникнути несумісності, дотримуйтеся дозволеного набору символів.
Не передавайте в параметрах персональні дані користувачів.
Рекомендований шаблон іменування. Використовуйте єдиний формат, щоб рекламні розміщення було легко знаходити у звітах:
ad_<month>_<source>_<creative>Приклади:
ad_sep_tgads_video1ad_sep_blogger_anna
6. Рекламні посилання та реферальні посилання — не одне й те саме
Реферальне посилання дозволяє користувачеві запрошувати інших людей і отримувати винагороду.
Рекламне посилання потрібне для вимірювання трафіку з рекламного розміщення. Саме по собі воно не повинно нараховувати користувачеві реферальну винагороду.
Розділяйте ці типи посилань за допомогою префіксів:
ref_…— реферальні посилання користувачів.ad_…— посилання рекламних розміщень.
Створення окремого реферального посилання для кожної рекламної кампанії — лише тимчасове рішення. Воно може призводити до нарахування реферальних винагород за рекламний трафік і змішування статистики.
7. Як рахувати кліки за посиланнями
Telegram не надає статистику натискань на посилання t.me.
Якщо вам потрібно рахувати кліки, спрямовуйте користувачів спочатку через власний редирект, а потім у Telegram.
Приклад:
https://yourdomain.com/go/ad_sep_anna → https://t.me/YourBot?start=ad_sep_annaВаш сервер реєструє клік і перенаправляє користувача на кінцеве посилання. Такий підхід потребує власної реалізації та не замінює облік запусків, нових користувачів або вступів.
8. Як вести таблицю результатів
Заведіть таблицю з одним рядком на кожне унікальне посилання.
Рекомендовані стовпці:
| Поле | Що записувати |
|---|---|
| Параметр посилання | Наприклад, ad_sep_anna |
| Розміщення | Назва каналу, публікації, блогера або оголошення |
| Дати | Період розміщення |
| Витрати | Витрати на розміщення |
| Нові користувачі | Кількість нових користувачів, атрибутованих посиланню |
| Вартість користувача | Витрати ÷ кількість нових користувачів |
9. Перевірка перед запуском
Перед публікацією реклами переконайтеся, що:
- Для кожного розміщення створено окреме посилання; посилання не використовуються повторно в інших розміщеннях.
- Параметр не перевищує максимальну кількість символів і містить лише допустимі символи.
- Посилання перевірено з другого акаунта: вступ враховується або параметр зберігається в боті/Mini App.
- Посилання, назву розміщення та витрати внесено до таблиці.
Частина 2. Реалізація для розробників
Приклади нижче використовують Python, SQL і бібліотеку aiogram 3 для бота. Ті самі принципи можна реалізувати на іншому технологічному стеку.
Код є основою реалізації: назви функцій доступу до бази даних і деякі деталі інтеграції необхідно адаптувати під ваш застосунок.
10. Які дані зберігати
Для атрибуції потрібні три сутності:
- Довідник рекламних посилань і кампаній.
- Джерело залучення користувача, яке зберігається під час створення користувача.
- Історія відвідувань рекламних посилань, включно з переходами наявних користувачів.
Приклад схеми SQL:
-- Один запис на кожне рекламне посилання.
-- Наприклад, параметр "ad_sep_anna" відповідає коду "sep_anna".
CREATE TABLE campaigns (
code text PRIMARY KEY,
name text NOT NULL,
created_at timestamptz NOT NULL DEFAULT now()
);
-- Джерело залучення користувача встановлюється під час створення.
-- NULL означає органічного користувача.
ALTER TABLE users
ADD COLUMN campaign text REFERENCES campaigns (code);
-- Усі користувачі, які відкривали рекламні посилання,
-- включно з новими та наявними користувачами.
CREATE TABLE campaign_visits (
code text REFERENCES campaigns (code),
user_id bigint,
first_at timestamptz NOT NULL DEFAULT now(),
PRIMARY KEY (code, user_id)
);Поле code має містити короткий код кампанії, наприклад sep_anna. Поле name призначене для опису розміщення, наприклад Публікація в Анни, вересень.
Таблиця campaign_visits потрібна для обліку відвідувань рекламних посилань окремо від первинного джерела залучення. Первинне джерело користувача не слід перезаписувати під час кожного нового переходу.
11. Читання параметра: один парсер для бота та міні-застосунку
Використовуйте єдиний парсер для рекламних і реферальних параметрів.
import re
AD = re.compile(r"ad_([A-Za-z0-9_-]{1,61})")
REF = re.compile(r"ref_([A-Za-z0-9]{4,32})")
def parse_start(param: str | None) -> tuple[str, str] | None:
"""Повертає ("ad", code), ("ref", code) або None."""
if not param:
return None
if m := AD.fullmatch(param):
return "ad", m[1]
if m := REF.fullmatch(param):
return "ref", m[1]
return NoneПісля читання перевірте, чи існує отриманий код у таблиці campaigns.
- Невідомий код не слід приписувати наявній кампанії: вважайте такий перехід органічним або неатрибутованим.
- Не зберігайте необроблене значення параметра без перевірки.
- Застосовуйте той самий підхід до параметрів, отриманих ботом і Mini App.
12. Бот: обробка команди /start
Під час запуску бота Telegram передає параметр в аргументах команди /start.
Приклад для aiogram 3:
@router.message(CommandStart())
async def start(message: Message, command: CommandObject):
source = parse_start(command.args)
# "/start ad_sep_anna" -> ("ad", "sep_anna")
async with db.transaction():
await create_user_if_new(message.from_user, source)
if source and source[0] == "ad":
await record_visit(source[1], message.from_user.id)Функція create_user_if_new має створювати запис користувача лише в тому разі, якщо користувач ще не існує.
Для запобігання дублюванню використовуйте атомарну операцію, наприклад:
-- create_user_if_new: атомарно, безпечно при одночасному запиті від бота та міні-застосунку
INSERT INTO users (id, campaign, referrer_id)
VALUES ($1, $2, $3)
ON CONFLICT (id) DO NOTHING
RETURNING id; -- повернутий рядок = новий користувач; нічого не повернуто = наявний користувач, залишений як єЯкщо запит повернув рядок, користувача створено. Якщо не повернув — користувач уже існує, і його первинне джерело залучення має залишитися без змін.
Для запису відвідування рекламного посилання можна використати:
-- record_visit
INSERT INTO campaign_visits (code, user_id)
VALUES ($1, $2)
ON CONFLICT DO NOTHING;Якщо наявний користувач знову відкриває посилання й отримує /start ad_…, збережіть відвідування, але не перезаписуйте його поле campaign.
Для реферальної атрибуції зберігайте referrer_id лише для нових користувачів. Не дозволяйте користувачеві вказувати самого себе як реферера.
13. Mini App: обробка першого запуску
Mini App може отримати параметр start_param разом із даними запуску Telegram Web App.
На фронтенді передавайте серверу підписані дані ініціалізації Telegram:
// Фронтенд: кожен запит містить підписані дані ініціалізації Telegram
fetch("/api/me", { headers: { Authorization: `tma ${Telegram.WebApp.initData}` } })На сервері необхідно перевірити справжність initData і термін його дії, перш ніж використовувати ідентифікатор користувача або start_param.
Приклад перевірки на Python:
import hashlib, hmac, json, time
from urllib.parse import parse_qsl
def check_init_data(
raw: str,
bot_token: str,
max_age: int = 86400
) -> dict:
fields = dict(
parse_qsl(
raw,
keep_blank_values=True,
strict_parsing=True
)
)
received = fields.pop("hash", "")
# усі поля, крім hash, включно з "signature", відсортовані, по одній парі key=value (ключ=значення) на рядок
data = "\n".join(
f"{k}={v}" for k, v in sorted(fields.items())
)
secret = hmac.new(
b"WebAppData",
bot_token.encode(),
hashlib.sha256
).digest()
expected = hmac.new(
secret,
data.encode(),
hashlib.sha256
).hexdigest()
if not hmac.compare_digest(expected, received):
raise PermissionError("bad signature")
if time.time() - int(fields["auth_date"]) > max_age:
raise PermissionError("expired")
return {
"user": json.loads(fields["user"]),
"start_param": fields.get("start_param")
}Після успішної перевірки використовуйте той самий принцип, що й у боті (create_user_if_new і record_visit):
- Отримайте
userіstart_paramіз перевірених даних. - Розберіть параметр за допомогою
parse_start. - Створіть користувача, лише якщо його ще немає.
- Запишіть відвідування рекламного посилання, якщо параметр відповідає відомій рекламній кампанії.
Безпека: використовуйте лише перевірені дані initData. Не довіряйте initDataUnsafe і параметрам URL як джерелам ідентифікатора користувача або атрибуції: їх можна підробити.
Параметр start_param передається під час запуску за відповідним посиланням. Під час наступних запусків із меню він буде відсутній. Тому первинне джерело залучення встановлюйте під час створення користувача, а не під час кожного запуску застосунку.
14. Один користувач — два способи входу
Бот і Mini App можуть використовувати одну таблицю користувачів, у якій користувач ідентифікується за Telegram user ID.
Наприклад, користувач спочатку запускає бота, а потім відкриває Mini App. Або навпаки.
Правило атрибуції:
- Перший обробник, що створив користувача, встановлює первинне джерело залучення.
- Другий обробник не повинен перезаписувати це джерело.
- Історію подальших переходів можна зберігати окремо в
campaign_visits.
Використовуйте атомарне створення запису, наприклад INSERT … ON CONFLICT DO NOTHING. Це допомагає уникнути помилок, якщо запити від бота та Mini App надходять майже одночасно.
15. Канали: облік вступів за запрошувальними посиланнями
Якщо вам потрібен власний облік вступів, а не лише статистика в інтерфейсі Telegram, створюйте окреме запрошувальне посилання для кожної кампанії та зберігайте його разом із кодом кампанії.
Приклад створення посилання на Python:
# Створити посилання для кожної кампанії та зберегти його разом із кодом
link = await bot.create_chat_invite_link(
CHANNEL_ID,
name="ad_sep_anna"
) # назва: від 1 до 32 символів
save_channel_link("ad_sep_anna", link.invite_link)Назва запрошувального посилання в цьому прикладі обмежена 1–32 символами.
Щоб отримувати події про вступи, бот має бути адміністратором каналу й отримувати відповідні оновлення chat_member і, якщо використовується схвалення заявок, chat_join_request.
Приклад налаштування polling:
# Вступи надходять як оновлення chat_member: бот має бути адміністратором і запитувати їх
await dp.start_polling(
bot,
allowed_updates=[
"message",
"chat_member",
"chat_join_request"
]
)Приклад обробки вступу:
@router.chat_member()
async def member(update: ChatMemberUpdated):
joined = (
update.old_chat_member.status in ("left", "kicked")
and update.new_chat_member.status == "member"
)
if joined and update.invite_link:
save_channel_join(
update.invite_link.name,
update.new_chat_member.user.id
)Якщо для посилання ввімкнено схвалення адміністратором, обробляйте chat_join_request. Запрошувальне посилання доступне в update.invite_link; після перевірки заявки можна викликати approve_chat_join_request.
За потреби записуйте також виходи користувачів, щоб оцінювати, хто залишився в каналі.
Telegram уже показує адміністраторам кількість вступів за кожним запрошувальним посиланням. Власна база даних потрібна, якщо ви хочете об'єднати дані про вступи з інформацією про користувачів бота або іншою аналітикою.
16. Підрахунок кліків через редирект (опційно)
Щоб рахувати кліки до переходу в Telegram, створіть власний редирект.
Приклад на Python для Mini App:
@app.get("/go/{code}")
async def go(code: str, request: Request):
agent = request.headers.get("user-agent", "")
if code_exists(code) and "TelegramBot" not in agent: # ігнорувати пошуковий робот Telegram для прев'ю посилань
record_click(code)
return RedirectResponse(
f"https://t.me/{BOT}?startapp=ad_{code}",
status_code=302
)У прикладі перевіряється код і виключаються запити, у User-Agent яких міститься TelegramBot, щоб не враховувати попередній перегляд посилання як звичайний клік користувача.
Реалізацію необхідно адаптувати до вашої інфраструктури та перевірити на реальних посиланнях. Редирект має спрямовувати користувача на правильне посилання бота або Mini App з відповідним параметром.
17. Приклад звіту
Наступний запит показує для кожної кампанії кількість унікальних відвідувачів рекламних посилань, нових користувачів і активованих користувачів.
SELECT
c.code,
c.name,
(
SELECT count(*)
FROM campaign_visits v
WHERE v.code = c.code
) AS visitors,
(
SELECT count(*)
FROM users u
WHERE u.campaign = c.code
) AS new_users,
(
SELECT count(*)
FROM users u
WHERE u.campaign = c.code
AND u.first_action_at IS NOT NULL
) AS active
FROM campaigns c
ORDER BY new_users DESC;
-- first_action_at: коли користувач уперше виконав дію, за яку платить кампанія (завдання, покупка)У цьому прикладі first_action_at — час першої цільової дії користувача, за яку платить рекламодавець, наприклад виконання завдання або покупки.
Показник visitors відображає користувачів, для яких збережено відвідування відповідної кампанії в campaign_visits; він не дорівнює кількості кліків за посиланням, якщо кліки не реєструються окремим редиректом.
18. Типові помилки та обмеження
- Бот отримує параметр лише після натискання
Start. Не всі користувачі, які натиснули на посилання, запускають бота. Тому кількість запусків може бути меншою за кількість кліків. - Повторний запуск не означає нового користувача. Якщо користувач видалив чат і запустив бота повторно, параметр може передатися ще раз, але користувач не стає новим.
- Не перезаписуйте первинне джерело залучення. Для аналізу подальших переходів використовуйте таблицю відвідувань
campaign_visitsз часовими мітками. - Розділяйте нові та наявні акаунти. Якщо завдання — рахувати залучення, повторні відвідування не повинні збільшувати кількість нових користувачів.
- Виключайте ботів і самореферали. Перевіряйте
is_botі не дозволяйте користувачеві посилатися на самого себе. - Дотримуйтеся обмежень параметрів. Загальна довжина параметра
start— не більше 64 символів. Використовуйте короткі коди, наприкладsep_anna, щоб залишити місце для префіксаad_абоref_. - Не змішуйте реферальну та рекламну атрибуцію. Різні префікси та правила обробки дозволяють уникнути помилкових нарахувань і звітів.