Users
The Users page lists the unique users who interacted with your bot within the selected time range.
What this page shows
Every row of the table contains:
| Column | Description |
|---|---|
| User ID | The identifier the producer recorded the event under. For private chats this is the user's Telegram ID; for group messages the MTProto worker records the chat ID here, and the real author is in $tg.from_id, which is what the user metrics count |
| Name | First and last name from the Telegram profile |
| Username | @username |
| Interface language | $tg.language_code, for example en |
| Telegram Premium | "Yes" or "No". A dash means Metriox has never received this user's status: for example, the user is known only from events, without a full profile. A dash does not mean "No" |
| Deep-link parameter | $tg.start_raw: the /start parameter the user arrived through |
| First seen, Last seen | First and last interaction in the selected period |
| Events in Range | Number of events for this user in the selected period |
The profile columns carry the same names as the attributes in the "Profile" group of User conditions in filters and read the same values: if a "Deep-link parameter" condition with the value promo found a user, their row shows promo.
The columns are always shown, even when nobody on the page has a value: a dash in a cell means the value was not recorded.
The user card that opens when you click a row lists the same properties in the same order. Under each one it shows where the value is stored and what is stored there. For example, "No" for Telegram Premium was read from $tg.is_premium = false, and "not recorded" means nothing has arrived at that path.
User profile properties ($tg.*)
When you connect with a Telegram bot token, Metriox automatically stores the user's properties from Telegram:
| Property | Type | Description |
|---|---|---|
$tg.telegram_user_id | number | The user's Telegram id |
$tg.first_name | string | First name |
$tg.last_name | string | Last name (if set) |
$tg.username | string | Telegram username (if set) |
$tg.language_code | string | Language code (for example, "ru", "en") |
$tg.is_premium | boolean | Premium status (if Telegram reports it) |
Where a profile comes from, and why it can be empty
Most Telegram accounts have no @username, and a name arrives only on updates where Telegram attached the from object. So a user can appear in the list with nothing but an identifier — they exist and are counted everywhere, there is simply nothing to call them yet.
What fills a profile:
- Mini App —
initDatacarries the full identity, so the profile is always filled. - Server SDK (Bot API) — identity arrives when you pass the whole update to the SDK (see SDK). Without that Metriox still recovers
@usernamefrom the events themselves, but the name, language and Premium flag stay unknown. - Bot token connection (MTProto) — Telegram does not hand a bot its private chats, so this path fills no profiles for DMs; in groups and channels it does.
History from before Metriox cannot be recovered: Telegram has no method that returns the list of people who have written to a bot. Only what happens after connecting is counted.
Periods in attribute breakdowns
A breakdown by language, Premium or campaign counts the users who were active in the selected period, and reads their profile as of now. Someone whose profile was written six months ago but who wrote yesterday appears in yesterday's report. Someone active but still nameless lands in the "unset" bucket.
The /start parameter
A deep link t.me/YourBot?start=<parameter> hands the bot a value when someone opens the chat from it. A Mini App link with startapp=<parameter> works the same way. Telegram delivers only latin letters, digits, underscore and hyphen, up to 64 characters: a link with anything else (&, =, %26, a space, Cyrillic) never reaches the bot, and nothing is recorded.
Metriox stores:
| Property | Type | Description |
|---|---|---|
$tg.start_raw | string | The whole parameter as received. Always recorded |
$tg.start_source | string | Value of the source key |
$tg.start_medium | string | Value of the medium key |
$tg.start_campaign | string | Value of the campaign key |
$tg.start_content | string | Value of the content key |
$tg.start_term | string | Value of the term key |
$tg.start_ref | string | Value of the ref key |
Named values are read out of the parameter in one format: an underscore separates pairs, a hyphen separates the name from the value. Only these six names are recognised, and the case of the name does not matter.
Example: the link t.me/YourBot?start=source-tgads_campaign-june records:
$tg.start_raw = "source-tgads_campaign-june"
$tg.start_source = "tgads"
$tg.start_campaign = "june"
A referral link t.me/YourBot?start=ref-a1b2c3 records $tg.start_ref = "a1b2c3".
- A parameter with none of the six names (
promo_june, an opaque ad token) is recorded in$tg.start_rawonly. Nothing is invented from it. - A value cannot contain an underscore, because the underscore separates pairs. Use a hyphen inside a value:
campaign-summer-salegivessummer-sale. - Values are case sensitive:
Juneandjuneare different values. - Parsing can be switched off for a single bot: bot settings, the Integrations section, the Read campaign tags from links switch.
$tg.start_rawis still recorded, but people who arrive while it is off get no tags, and they are not added later. The same place has a field to try a link and see what would be recorded. - Parsing is not applied retroactively: people who arrived before it shipped have
$tg.start_rawonly.
Select users who came through a given link with a "Deep-link parameter" condition using the "contains" operator.
If a person arrived through different links, the profile shows one of them, usually the latest. Right after a new visit the previous one may show for a while. Which link a person is credited to in reports is chosen by the Attribution control (see Reports).
Earlier versions of this page described a parameter like ref=123&campaign=promo parsed into $tg.start.<key> fields. Telegram cannot deliver such a parameter, and those fields were never recorded for any bot. Use the format above.
The profile is updated when Telegram tells Metriox something new about the user. Each property comes from a record that has it, so a later, thinner record does not erase a name or a deep link that is already known.
Filtering users
The Users page uses the same filters as widgets. Use event conditions to find users who performed specific actions, and User conditions to select them by language, Premium, name or deep-link parameter (the "Profile" group) or by how much they did in the period (the "Activity" group).
Save a filter as a segment
A filter you have built can be saved as a segment and then applied in reports and broadcasts. This page is the best place to build one: the table shows who falls into it for the selected period before you save. You can apply a saved segment here too, change its conditions and press "Update". Every segment in the project is in the Segments section of the menu on the left, and from there a segment opens straight on this page.
User card
Click a user row to open their card. It holds everything Metriox knows about the person:
- User: the ID, events in the period, first and last visit
- Telegram profile: every recorded profile property, under the same names as in filters, with the property key beneath each
- Other properties: anything else the profile holds, as stored
- A button to jump to the user's events, and the Conversation tab
Click any value to copy it.
What's next?
- Filters — segment users by events and properties
- Segments — save a filter and apply it in reports and broadcasts
- Metrics — more about the Events, Users, and Events per User metrics
- Automatic setup — how to enable automatic profile capture