Бот получает пользователей из рекламы, постов в каналах, партнёрских ссылок и поиска Telegram. Если не размечать эти источники, через месяц непонятно, что из них работает, а что просто съедает бюджет. В Telegram для этого есть встроенный механизм — ссылки с параметром start. Разберём, как их генерировать, принимать в боте на aiogram 3, хранить и считать, и на каких мелочах легко ошибиться.

Как устроена ссылка с параметром start

Обычная ссылка на бота выглядит как https://t.me/your_bot. Если добавить к ней параметр, получится deep link:

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

Когда человек открывает такую ссылку и нажимает «Запустить», бот получает сообщение /start src_dzen_oct. Всё, что после пробела, — ваша метка.

Ограничения у параметра такие:

  • не длиннее 64 символов;
  • только латиница, цифры, _ и - — без пробелов, кириллицы, точек и =.

Если в метку нужно положить что-то сложнее, её кодируют в base64url. aiogram умеет делать это сам, но помните: после кодирования строка становится длиннее примерно на треть, и лимит в 64 символа применяется уже к закодированному значению.

Подробно про форматы ссылок, startgroup для групп и отдельные ссылки для рекламы мы писали в статье как сделать ссылку на Telegram-бота с параметром Start.

Генерируем ссылки

Для простых меток кодирование не нужно — читаемые значения удобнее разбирать в отчётах:

from aiogram import Bot from aiogram.utils.deep_linking import create_start_link SOURCES = ["dzen_oct", "tg_ads_1", "partner_ivan", "seo_blog"] async def make_links(bot: Bot) -> dict[str, str]: return {src: await create_start_link(bot, f"src_{src}") for src in SOURCES} 

Если метка содержит недопустимые символы, передайте encode=True — aiogram закодирует её в base64url:

link = await create_start_link(bot, "promo:october/2026", encode=True) 

Принимаем параметр в боте

В aiogram 3 для этого есть фильтр CommandStart(deep_link=True) и объект CommandObject, в котором лежит сам параметр:

from aiogram import Router from aiogram.filters import CommandObject, CommandStart from aiogram.types import Message router = Router() @router.message(CommandStart(deep_link=True)) async def start_with_source(message: Message, command: CommandObject): save_user(message.from_user.id, command.args) await message.answer("Привет! Рад, что вы здесь.") @router.message(CommandStart()) async def start_plain(message: Message): save_user(message.from_user.id, None) await message.answer("Привет! Рад, что вы здесь.") 

Порядок важен: обработчик с deep_link=True должен стоять раньше обычного /start, иначе метки до него не дойдут. Если вы кодировали метку, раскодируйте её через decode_payload из aiogram.utils.deep_linking.

Храним первый источник пользователя

Для начала хватит SQLite. INSERT OR IGNORE сохраняет только первый источник — так вы не перезапишете метку, если человек потом откроет бота по другой ссылке:

import sqlite3 db = sqlite3.connect("bot.db") db.execute( "CREATE TABLE IF NOT EXISTS users (" " user_id INTEGER PRIMARY KEY," " source TEXT," " first_seen TEXT DEFAULT CURRENT_TIMESTAMP)" ) def save_user(user_id: int, source: str | None) -> None: db.execute( "INSERT OR IGNORE INTO users (user_id, source) VALUES (?, ?)", (user_id, source or "direct"), ) db.commit() 

Считаем, какой источник работает

Сколько пользователей пришло из каждого источника за последний месяц:

SELECT source, COUNT(*) AS users FROM users WHERE first_seen >= date('now', '-30 days') GROUP BY source ORDER BY users DESC; 

Число запусков — только половина картины. Добавьте таблицу целевых действий (оплата, заявка, подписка на канал) и считайте конверсию по источникам: часто дешёвый источник приводит много людей, которые ничего не делают дальше. Какие ещё показатели стоит смотреть, мы разобрали в статье про статистику Telegram-бота.

Подводные камни

  • Метку видит пользователь. Не кладите в неё ID заказов, промокоды и любые данные, которые нельзя показывать.
  • Одна ссылка — один источник. Если одну и ту же ссылку поставить и в рекламу, и в пост, данные смешаются.
  • Не все приходят по ссылке. Часть людей найдёт бота через поиск Telegram или по имени — они попадут в direct, и это нормально.
  • Лимит считают после кодирования. Длинная метка с encode=True легко вылезает за 64 символа.

Метрика, которую видят все: monthly users

В профиле бота Telegram показывает, сколько людей пользовались им за месяц. Эту цифру видит каждый, кто открывает бота, и по ней судят, живой ли он. По наблюдениям владельцев ботов, активная аудитория помогает и в поиске Telegram, где боты конкурируют за те же ключевые слова, что и каналы. Пошаговый план мы собрали в статье как продвигать Telegram-бота.

Когда нужно поднять этот счётчик под конкретный ключ, используют Premium Bot Start — запуски бота аккаунтами с Telegram Premium. Удобная деталь для разработчика: заказ принимает ссылку с параметром start. Дайте такому заказу отдельную метку, например ?start=src_premium_test, — и эти пользователи будут в вашей аналитике отдельной строкой, их легко сравнить с остальными источниками. Для простого первого объёма есть обычные старты бота, а прикинуть, сколько Premium-аудитории нужно под ваш ключ, помогает калькулятор поиска Telegram.

Чек-лист

  1. Для каждого источника — своя ссылка ?start=src_....
  2. Метки из латиницы, цифр, _ и -, не длиннее 64 символов; сложные — через encode=True.
  3. Обработчик CommandStart(deep_link=True) стоит раньше обычного /start.
  4. В базе хранится первый источник пользователя.
  5. Источники сравниваются по конверсии в целевое действие, а не только по числу запусков.

Больше материалов про продвижение каналов и ботов в Telegram — в блоге BoostTelega.