Telegram Crypto Channel Mentions
Daily counts of crypto token mentions in public Telegram channels - how often each channel named each token, how many distinct messages named it, and the total views those messages accumulated. Tokens are keyed on contract address where one was posted, so the panel survives ticker collisions.
telegram_coin_mentions - the dataset name to pass to the Obscura API.
What one row means
How many times one crypto token was mentioned across public Telegram channels on one day, and the reach of the messages that named it.
One row per (coin_key, available_date).
Point-in-time availability
Every Obscura dataset carries available_date: the calendar day the publisher made the row
available, day-of, with no session rounding. It is the one column a backtest filters on, and it means the
same thing on every dataset in the catalog.
For telegram_coin_mentions: published: a Telegram channel post is readable by anyone the instant it is posted, so available_date is the UTC calendar day of the post itself and there is no publication lag to model - the event and its availability are the same act. Measured 2026-09-03 against t.me/s/<channel>, whose per-message <time datetime=...> carries a full UTC timestamp (e.g. 2015-10-28T18:20:58+00:00); available_date is that timestamp's UTC date. There is deliberately NO occurred_on: it would equal available_date on every row. TWO honest limits, both structural rather than fixable. (1) views_sum is a LIFETIME counter read at scrape time, not a point-in-time value - views_observed_on records the day it was read, and the two columns are only interchangeable when they are close, which holds for forward daily capture and fails for the historical backfill. (2) Deleted messages are absent from the source entirely, so history under-represents tokens whose promotion was later scrubbed; this is survivorship bias in the direction that most flatters the tokens, and it is why the collector runs forward daily rather than relying on backfill.
Refresh cadence
Obscura refreshes telegram_coin_mentions daily - the most frequent scheduled job that re-collects or re-exports it. This is Obscura's own pipeline cadence, not the upstream publisher's release schedule; when a row became public is recorded per row in available_date.
Schema - 10 columns
The full public column list for telegram_coin_mentions, with the meaning of every field. The same
schema is served unauthenticated at https://api.obscura.trade/v1/catalog/telegram_coin_mentions.
| Column | Type | Description |
|---|---|---|
| coin_key | text · not null | WHICH TOKEN, canonically. `evm:0x…` for an Ethereum-style contract address, `sol:<base58>` for a Solana mint, or `sym:<TICKER>` when the message named a ticker and no address. The prefix is part of the key rather than a separate column being joined on, so the ambiguous rows cannot be silently mixed with the unambiguous ones: `sym:MOON` is honestly a different key from any particular MOON contract, because the source did not say which one it meant. |
| available_date | date · not null | PUBLIC-AVAILABILITY DATE — the UTC day the messages were posted, which for a public channel is the day they became readable. **The point-in-time column.** |
| coin_kind | text · not null | HOW THE TOKEN WAS IDENTIFIED, and therefore how much to trust the key: `contract_evm` and `contract_solana` are globally unique addresses; `cashtag` is a `$TICKER` written as such; `symbol` is a bare uppercase token matched against a known-symbol list. The two contract kinds are the only ones safe to join across channels without further disambiguation. Filter on this before treating the panel as token-level truth. |
| coin_symbol | text | The ticker as the channel wrote it (`DOGE`, `PEPE`), upper-cased, when the message carried one. NULL when only a bare contract address was posted - common in early-stage promotion, where the address IS the call. Display and grouping only; it is not unique and must never be a join key. |
| contract_address | text | The raw contract address exactly as posted, preserving its original checksum casing, when `coin_kind` is a contract kind. NULL otherwise. This is the column to join to an on-chain dataset. |
| mention_count | integer · not null | HOW MANY TIMES the token was named that day across every watched channel, counting every occurrence - a message naming the same token three times contributes three. The promotion-intensity measure. |
| message_count | integer · not null | HOW MANY DISTINCT MESSAGES named the token that day. Always `<= mention_count`, and the two diverge exactly when posts repeat a token within themselves, which is itself a promotion signal. |
| channel_count | integer · not null | HOW MANY DISTINCT CHANNELS named the token that day. The breadth measure, and the one that separates the two things a raw mention count cannot tell apart: a single channel spamming a token 500 times, and 50 channels each mentioning it 10 times. Co-ordinated promotion looks like the second and is the more interesting signal. Deliberately a COUNT and not a list: which channels said it is collector state, not product, and naming them would put third-party account handles into an exported dataset. |
| views_sum | bigint | TOTAL VIEWS across the messages that named the token, as Telegram reported them **at scrape time** - the reach of the day's promotion. **NOT POINT-IN-TIME.** Telegram serves a lifetime counter, so a row backfilled years after the fact carries views the post accumulated long after its `available_date`. Read `views_observed_on` before using this in anything time-sensitive. NULL when the source published no view count. |
| views_observed_on | date | THE DAY `views_sum` WAS READ FROM TELEGRAM, which is what makes that column safe to publish at all. When this is within a day or two of `available_date` the view count is effectively point-in-time and can be used as of the row's date. When it is far later - every row written by the historical backfill - the count is a lifetime total that leaks the future and must be excluded from any backtest. NULL exactly when `views_sum` is NULL. Taken from the CAPTURE time of the source pages, never from the clock when the row was written, so re-running the collector reproduces this value exactly. Where a day's messages came from pages captured at different times, this is the LATEST of them - the point by which every contributing count had been observed. |
Access telegram_coin_mentions
Two delivery paths, one identifier. Both require an Obscura account and an active subscription; the catalog entry and the schema above are public.
import obscura
client = obscura.Client("obs_live_…")
df = client.query(
dataset="telegram_coin_mentions",
symbols=["NVDA", "AAPL"],
start="2024-01-01",
)
Create a free account Browse all 122 datasets
Frequently asked questions
What is in the telegram_coin_mentions dataset?
Daily counts of crypto token mentions in public Telegram channels - how often each channel named each token, how many distinct messages named it, and the total views those messages accumulated. Tokens are keyed on contract address where one was posted, so the panel survives ticker collisions. How many times one crypto token was mentioned across public Telegram channels on one day, and the reach of the messages that named it.
How do I avoid look-ahead bias with telegram_coin_mentions?
Filter on telegram_coin_mentions.available_date, the day the publisher made the row public. For this dataset that date is derived as follows - published: a Telegram channel post is readable by anyone the instant it is posted, so available_date is the UTC calendar day of the post itself and there is no publication lag to model - the event and its availability are the same act. Measured 2026-09-03 against t.me/s/<channel>, whose per-message <time datetime=...> carries a full UTC timestamp (e.g. 2015-10-28T18:20:58+00:00); available_date is that timestamp's UTC date. There is deliberately NO occurred_on: it would equal available_date on every row. TWO honest limits, both structural rather than fixable. (1) views_sum is a LIFETIME counter read at scrape time, not a point-in-time value - views_observed_on records the day it was read, and the two columns are only interchangeable when they are close, which holds for forward daily capture and fails for the historical backfill. (2) Deleted messages are absent from the source entirely, so history under-represents tokens whose promotion was later scrubbed; this is survivorship bias in the direction that most flatters the tokens, and it is why the collector runs forward daily rather than relying on backfill. A query of the form WHERE available_date <= '<as-of date>' never sees a row before it existed.
In what formats can I get telegram_coin_mentions?
As a Parquet bulk export (POST https://api.obscura.trade/v1/download) or as JSON from the typed query API (POST https://api.obscura.trade/v1/query), both with dataset="telegram_coin_mentions". The column schema is public at https://api.obscura.trade/v1/catalog/telegram_coin_mentions.
Can I filter telegram_coin_mentions by company or symbol?
Yes. telegram_coin_mentions carries coin_key, the column the API's symbols filter resolves against.
How often is telegram_coin_mentions updated?
Obscura refreshes telegram_coin_mentions on a daily schedule - that is the most frequent scheduled job that re-collects or re-exports the table. It is Obscura's own pipeline cadence, not the upstream publisher's release schedule; when the publisher makes a row available is described by the availability rule above, and is recorded per row in available_date.