Skip to content

Встроенная аналитика Telegram ​

Telegram предоставляет инструменты для анализа результатов рекламных размещений с помощью уникальных ссылок. Вы можете создавать отдельную ссылку для каждого рекламного размещения. Для каналов и групп статистика вступлений доступна непосредственно в Telegram, а для ботов и Mini Apps необходимо дополнительно настроить сохранение параметров ссылок и сбор данных на стороне проекта.

ВНИМАНИЕ

Одно рекламное размещение — одна уникальная ссылка. Если использовать одну ссылку в нескольких объявлениях, источники трафика смешаются, и разделить их задним числом не получится.

Этот способ аналитики работает отдельно от статистики кампаний и отслеживания конверсий AdsGram.

Часть 1. Для менеджеров кампаний на стороне рекламодателя ​

1. Создавайте отдельную ссылку для каждого рекламного размещения ​

Чтобы сравнивать результаты разных рекламных размещений, используйте уникальную ссылку для каждого из них.

Например, если вы продвигаете проект в трёх Telegram-каналах, создайте три отдельные ссылки. Это позволит определить, какие размещения привлекают больше пользователей.

Тип ссылки зависит от того, куда ведёт реклама:

Куда ведёт рекламаФормат ссылкиГде отслеживать результат
Telegram-канал или группаОтдельная пригласительная ссылкаTelegram: настройки канала или группы → пригласительные ссылки
Ботt.me/YourBot?start=ad_sep_annaВаш бот, если он сохраняет параметр
Mini Appt.me/YourBot?startapp=ad_sep_annaСервер вашего приложения, если он сохраняет параметр

Замените YourBot на имя своего бота, а ad_sep_anna — на уникальный параметр рекламного размещения.

2. Каналы и группы: пригласительные ссылки ​

Создавайте отдельную пригласительную ссылку для каждого рекламного размещения.

  1. Откройте канал или группу и нажмите на её название.
  2. Перейдите в настройки редактирования. В десктопной версии откройте меню ⋮ → Управление каналом / Управление группой.
  3. Откройте раздел Пригласительные ссылки и выберите Создать новую ссылку.
  4. Укажите название, соответствующее размещению, например ad_sep_anna. Название видно только администраторам, но не пользователям, которые переходят по ссылке.
  5. При необходимости задайте срок действия ссылки, ограничение по количеству пользователей или необходимость одобрения заявки на вступление администратором.
  6. Используйте ссылку только в одном рекламном размещении.

Где смотреть статистику: в разделе Пригласительные ссылки Telegram показывает количество пользователей, вступивших по каждой ссылке. Открыв конкретную ссылку, можно посмотреть список пользователей.

Обычная публичная ссылка вида t.me/yourchannel не позволяет разделить вступления по рекламным размещениям. Публичные каналы тоже могут создавать пригласительные ссылки — используйте отдельные ссылки в рекламе.

3. Боты: ссылки с параметром start ​

Используйте ссылку следующего формата:

https://t.me/<bot>?start=<parameter>

Например:

https://t.me/YourBot?start=ad_sep_anna

Когда пользователь переходит по ссылке и нажимает Start, бот получает команду с параметром:

/start ad_sep_anna

Telegram не ведёт автоматическую статистику таких переходов и запусков по рекламным параметрам. Бот должен самостоятельно сохранять параметр при первом создании записи пользователя.

Учитывайте только новых пользователей, если ваша метрика — привлечение новых пользователей. Если существующий пользователь открывает рекламную ссылку, это не делает его новым пользователем.

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_video1
    • ad_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. Какие данные хранить ​

Для атрибуции нужны три сущности:

  1. Справочник рекламных ссылок и кампаний.
  2. Источник привлечения пользователя, который сохраняется при создании пользователя.
  3. История посещений рекламных ссылок, включая переходы существующих пользователей.

Пример схемы SQL:

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. Чтение параметра: один парсер для бота и мини-приложения ​

Используйте единый парсер для рекламных и реферальных параметров.

python
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:

python
@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 должна создавать запись пользователя только в том случае, если пользователь ещё не существует.

Для предотвращения дублирования используйте атомарную операцию, например:

sql
-- create_user_if_new: атомарно, безопасно при одновременном запросе от бота и мини-приложения
INSERT INTO users (id, campaign, referrer_id)
VALUES ($1, $2, $3)
ON CONFLICT (id) DO NOTHING
RETURNING id; -- возвращённая строка = новый пользователь; ничего не возвращено = существующий пользователь, оставлен как есть

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

Для записи посещения рекламной ссылки можно использовать:

sql
-- 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:

javascript
// Фронтенд: каждый запрос содержит подписанные инициализационные данные Telegram
fetch("/api/me", { headers: { Authorization: `tma ${Telegram.WebApp.initData}` } })

На сервере необходимо проверить подлинность initData и срок его действия, прежде чем использовать идентификатор пользователя или start_param.

Пример проверки на Python:

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):

  1. Получите user и start_param из проверенных данных.
  2. Разберите параметр с помощью parse_start.
  3. Создайте пользователя, только если его ещё нет.
  4. Запишите посещение рекламной ссылки, если параметр соответствует известной рекламной кампании.

Безопасность: используйте только проверенные данные 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:

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:

python
# Вступления приходят в виде обновлений chat_member: бот должен быть администратором и запрашивать их
await dp.start_polling(
    bot,
    allowed_updates=[
        "message",
        "chat_member",
        "chat_join_request"
    ]
)

Пример обработки вступления:

python
@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:

python
@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. Пример отчёта ​

Следующий запрос показывает по каждой кампании количество уникальных посетителей рекламных ссылок, новых пользователей и активированных пользователей.

sql
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_.
  • Не смешивайте реферальную и рекламную атрибуцию. Разные префиксы и правила обработки позволяют избежать ошибочных начислений и отчётов.