События
События — это основа аналитики в Metriox. Каждое действие пользователя в вашем Telegram-боте может быть записано как событие.
Что такое событие?
Событие — это любое действие или взаимодействие пользователя с вашим ботом:
- Нажатие на кнопку
- Отправка команды
- Просмотр экрана
- Завершение покупки
- Любое кастомное действие
Структура события
События в Metriox платформо-агностичны и состоят из:

Базовые поля
| Поле | Тип | Описание |
|---|---|---|
event_id | UUID | Уникальный идентификатор события |
event_name | String | Название события (например, message) |
platform_user_id | String | ID пользователя в Telegram |
session_id | UUID | ID сессии пользователя |
tenant_id | UUID | ID вашего бота в Metriox |
received_at | DateTime | Время получения события сервером |
created_at | DateTime | Время создания события |
Дополнительные поля
body(String, nullable) — текстовое содержимое событияprops(JSON) — произвольные свойства события в формате JSON
Единый формат независимо от источника
Данные в вашем боте могут собираться разными способами — через токен бота (опрос Telegram по MTProto), через серверный SDK поверх Bot API, через WebApp-SDK в браузере или напрямую по HTTP API. Независимо от источника Metriox приводит все события к одной канонической структуре на стороне сервера: одинаковые имена событий, одни и те же разделы $-свойств и одинаковые значения полей.
Это значит, что данные любого происхождения одинаково видны и доступны в дашборде, фильтрах и сегментах — вам не нужно знать, каким способом было собрано событие, чтобы построить по нему отчёт.
Приведение к канону выполняется один раз, на входе (ingest). Чем меньше преобразований — тем предсказуемее данные, поэтому SDK и воркер отдают поля максимально близко к финальному виду, а сервер лишь достандартизирует их. Историческим данным это не мешает: старые события дочитываются в том же каноническом виде.
Канонические имена событий (Telegram)
События из Telegram получают каноническое имя по смыслу действия, а не по способу доставки. Ключевой принцип: одно действие — одно имя, а детали выражаются свойствами.
Например, любое сообщение — входящее или исходящее, текстовое или с вложением, новое или отредактированное — это одно событие message. Различить их можно по свойствам:
| Свойство | Что показывает |
|---|---|
$tg.direction | outbound — ответ бота, inbound — сообщение пользователя |
$tg.is_edited | сообщение было отредактировано |
$tg.content_type | что было в сообщении (text, photo, voice, …) — одинаково на любом подключении |
$tg.message_type | исходное поле Bot API SDK; для группировок используйте content_type |
$tg.chat_type | тип чата (private, group, supergroup, channel) |
$tg.entities | форматирование текста (жирный, ссылки, код) |
Основные канонические имена:
| Имя события | Когда возникает |
|---|---|
message | любое сообщение (см. свойства выше) |
callback_query | нажата inline-кнопка |
inline_query | inline-запрос к боту |
chosen_inline_result | выбран inline-результат |
poll / poll_vote | опрос / голос в опросе |
reaction | реакция на сообщение |
pre_checkout_query, shipping_query, successful_payment | этапы оплаты |
my_chat_member, chat_member, chat_join_request | изменение участия в чате (в том числе блокировка бота) |
message_deleted | сообщения удалены |
business_message | сообщение через Telegram Business |
Metriox использует $tg.direction, чтобы показывать переписку двумя сторонами: сообщения пользователя — слева, ответы бота — справа.
Поле заполняется на любом источнике, но ответы бота нужно ещё уметь увидеть. Bot API принципиально не присылает боту его собственные отправленные сообщения, поэтому на Bot API их сообщает сам бот: оберните клиент через WithMetrioxCapture(...) в C#-SDK, и это произойдёт автоматически. Подключение по токену бота (MTProto) видит исходящие сообщения само, но не получает личные переписки — их приносит только SDK. Подробнее в SDK.
Идентификатор события и дедупликация
event_id вычисляется детерминированно из «естественных» координат Telegram — например, из идентификатора чата и идентификатора сообщения. Отсюда два практических следствия:
- повторная доставка не удваивает данные. Если Telegram или ваш бот отправит одно и то же обновление дважды (перезапуск, повтор вебхука, переподключение), это останется одним событием;
- двойное подключение не удваивает счёт. Если один и тот же бот подключён и по токену, и через SDK, оба способа вычислят для одного действия одинаковый
event_id.
Здесь легко ошибиться, поэтому точная формулировка:
| Результат | |
|---|---|
event_id у обеих копий | совпадает |
| Строк в хранилище | две — они не схлопываются в одну |
| Списывается из квоты событий | одна |
Строки намеренно остаются раздельными: у них разные $source.channel, а также могут различаться session_id и platform_user_id, поэтому отчёт с привязкой к конкретному источнику продолжает находить свои данные. Вторая копия помечается свойством $meta.unbilled_duplicate и не расходует квоту.
Дедупликация счёта работает не для всех типов событий: она применяется там, где оба способа подключения сообщают одинаковые «естественные» координаты Telegram — обычные сообщения, правки (если Telegram прислал время правки), нажатия кнопок, инлайн-запросы, платёжные запросы и сообщения бизнес-аккаунта.
Пока считаются отдельно: реакции, голоса в опросах и выбранные инлайн-результаты. Для остальных типов вопрос не стоит — их физически видит только один способ подключения, поэтому дубликата не возникает.
update_idМожет показаться, что для этого подходит update_id из Bot API. Он не подходит: update_id существует только в потоке getUpdates/вебхука Bot API, а в MTProto его нет вообще — там обновления нумеруются курсорами сессии (pts/qts), которые различаются у каждого клиента и не являются свойством самого события. Поэтому идентификатор строится из координат, которые видны обоим способам подключения.
Ваши кастомные события используют любое имя, которое вы задаёте (purchase_completed, screen_view, …), и помечаются как $event.origin = custom.
Свойства события
Свойства — это дополнительная информация о событии, которая позволяет более детально анализировать поведение пользователей.
Свойства бывают двух видов: системные (собираются платформой автоматически, начинаются с $) и пользовательские (ваши произвольные поля). Подробнее — в разделе Свойства.
Примеры свойств
{
"button_name": "купить_подписку",
"plan": "premium",
"price": 299,
"currency": "RUB",
"screen_name": "pricing"
}
Типы свойств
Metriox поддерживает следующие терминальные типы данных:
- String — текстовые значения
- Number — числовые значения (integer, float)
- DateTime — дата и время
- Boolean — true/false
Используйте понятные названия для кастомных событий и свойств. Например, вместо btn_1_click используйте subscription_button_click.
Примеры событий
Простое кастомное событие
{
"event_name": "bot_started",
"platform_user_id": "123456789",
"session_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
Кастомное событие со свойствами
{
"event_name": "purchase_completed",
"platform_user_id": "123456789",
"props": {
"product_id": "premium_month",
"amount": 299,
"currency": "RUB",
"payment_method": "telegram_stars"
}
}
Автоматически собранное сообщение из Telegram
Так выглядит команда /start premium от пользователя после приведения к канону. Имя события — message, а Telegram-детали лежат в системных разделах $event и $tg (только для чтения):
{
"event_name": "message",
"platform_user_id": "123456789",
"body": "/start premium",
"props": {
"$event": { "origin": "telegram", "type": "message" },
"$tg": {
"is_outgoing": false,
"chat_type": "private",
"command": "/start",
"command_params": "premium"
}
}
}
Отправка событий
События можно отправлять несколькими способами:
- SDK — используйте официальные SDK для JavaScript/TypeScript или C#
- API — отправляйте события через REST API
- Автоматически — Telegram-события собираются автоматически при подключении токена бота
Лучшие практики
Рекомендуется
- Используйте snake_case для названий кастомных событий:
button_click,purchase_completed - Добавляйте контекстные свойства:
screen_name,source,category - Группируйте похожие события через свойства, а не через десятки уникальных имён
Не рекомендуется
- Слишком общие названия:
click,action,event - Отправка персональных данных в открытом виде
- Слишком много уникальных событий (лучше использовать свойства)
Что дальше?
- Свойства — системные и пользовательские свойства
- Типы данных — подробнее о поддерживаемых типах данных
- Дашборд — как визуализировать события
- Фильтры — как фильтровать события для анализа