Перейти к содержанию
Innovialabs

Глубокие ссылки в Telegram: параметр start для трекинга и рефералок

Практика3 мин

Коротко

Добавьте к ссылке на бота ?start=КОД (или ?startapp=КОД для Mini App) — бот получит этот код при запуске, и вы узнаете, какая реклама, блогер или друг привели пользователя.

Как работает параметр start

Глубокая ссылка — обычная ссылка t.me с одним дополнительным параметром. Когда пользователь открывает https://t.me/your_bot?start=c_8f3k2 и нажимает Start, бот получает сообщение /start c_8f3k2.

Для Mini App параметр называется startapp: https://t.me/your_bot/app?startapp=c_8f3k2 открывает приложение и передаёт значение как start_param в данных запуска. Бот в этом случае сообщения не получает — значение доступно только внутри Mini App.

Одной ссылки на каждое размещение достаточно, чтобы понимать, откуда пришёл пользователь: из рекламной кампании, от блогера, по QR-коду на упаковке или по приглашению друга.

Правила для параметра

  • До 64 символов.
  • Допустимые символы: A-Z, a-z, 0-9, _ и -.
  • Без пробелов, =, & и кириллицы — поэтому UTM-строка целиком не поместится.
ПодходПримерКогда подходит
Короткий читаемый кодig_springКампаний немного
Поля с разделителямиsrc-ig__cmp-springНесколько атрибутов, без базы
ID из базы данныхc_8f3k2Кампаний много, связи могут меняться
Base64urlзакодированный JSONПроизвольные данные в пределах 64 символов

Самый практичный вариант — ID из базы: храните кампанию (источник, площадку, креатив, дату) в таблице, а в ссылку кладите только короткий ID. Ссылки остаются короткими, не раскрывают внутренние названия, а ошибку в разметке можно исправить без перевыпуска ссылок.

Обработка в aiogram и grammY

В aiogram 3 обработчик deep link регистрируется раньше обычного /start:

from aiogram import Router
from aiogram.filters import CommandStart, CommandObject
from aiogram.types import Message

router = Router()

@router.message(CommandStart(deep_link=True))
async def start_with_code(message: Message, command: CommandObject):
    await save_touch(message.from_user.id, command.args)
    await message.answer("Добро пожаловать!")

@router.message(CommandStart())
async def start_plain(message: Message):
    await message.answer("Добро пожаловать!")

В grammY значение доступно как ctx.match:

bot.command("start", async (ctx) => {
  const code = ctx.match; // пустая строка, если параметра нет
  if (code) await saveTouch(ctx.from!.id, code);
  await ctx.reply("Добро пожаловать!");
});

В Mini App Telegram.WebApp.initDataUnsafe.start_param подходит для решений в интерфейсе, но для атрибуции доверяйте только значению из initData, проверенной на сервере.

Атрибуция рекламного трафика

  1. Создайте запись кампании и отдельную ссылку для каждого размещения.
  2. При /start сохраняйте первое касание, только если пользователь новый. Последующие касания пишите в отдельную таблицу.
  3. Связывайте пользователей с целевыми событиями — регистрацией, заказом, оплатой — и считайте конверсии по кампаниям, а не только запуски.
  4. Пользователей без параметра помечайте как органику или «неизвестно»: Telegram не передаёт реферер, и тот, кто нашёл бота через поиск, придёт без кода.

Заранее решите, по какой модели строятся отчёты — первое или последнее касание. Пользователь может открывать разные ссылки в разное время, и смешение моделей делает цифры несопоставимыми.

Реферальная программа с защитой от накруток

Реферальная ссылка выглядит как ?start=ref_x7k2p. Используйте случайный код для каждого пользователя, а не Telegram ID: ID легко перебрать, и он раскрывает данные аккаунта.

Базовая защита:

  • Только новые пользователи. Если приглашённый уже был в базе — бонуса нет.
  • Запрет самоприглашения. Игнорируйте код, принадлежащий самому пользователю.
  • Награда за целевое действие, а не за /start. Нажать Start ничего не стоит, и фермы фейковых аккаунтов быстро выкачают программу «бонус за запуск».
  • Период удержания перед выплатой бонусов, чтобы успели проявиться возвраты и фрод.
  • Уникальное ограничение: одна реферальная запись на приглашённого, чтобы повторы и двойные нажатия не создавали дубли.
  • Лимиты и алерты: ограничьте число наград на одного пригласившего в день и отмечайте резкие всплески или приглашённых, которые ничего не делают после запуска.

Частые ошибки

  • Полная UTM-строка в ссылке: она нарушает правила символов, и параметр теряется.
  • Перезапись источника при каждом /start — исходная кампания пропадает.
  • Доверие к start_param с клиента без проверки на сервере.
  • Необработанный случай пустого параметра, из-за которого падает обработчик.

Частые вопросы

Да. Если пользователь откроет ссылку и снова запустит бота, тот получит /start с новым кодом. Поэтому нужно чёткое правило: первое касание или последнее.

Поможем с этим

Если хотите не разбираться самим, а получить результат — этим мы занимаемся каждый день.

Обсудить проект

Читайте также

Есть идея или задача? Расскажите нам

Ответим в течение рабочего дня и предложим решение. Консультация бесплатная.