Telegram Channel Data API: Posts and Views, No Bot Token
Pull any public Telegram channel's posts, views, reactions and media with one key and no bot token, and see what each field really contains.

Read a public Telegram channel's posts, views and reactions without a bot token. Paste this into your agent:
Set up https://monid.ai/SKILL.md, and then use Monid to pull the last 20 posts of the Telegram channel durov, turn the view counts into numbers, and give me a table with date, views, views per day since posting and link, sorted by views per day.
One prompt reads a channel. 1 min setup · 10-20 hrs saved.
You want what a public Telegram channel has posted, with the numbers attached, for one channel or a watchlist of fifty, without creating a bot or joining anything. This guide shows the quickest way to get that into your agent or a spreadsheet, what each record contains (we ran it live on 2026-10-16), and the traps we hit: rounded string views, a counter that grows with age, and message ids with holes. It runs through Monid, the OpenRouter for agent tools: one key, one balance, every tool priced per call.
What is the easiest way to get Telegram channel data through an API?
Monid. Install it once, add a key, and your agent calls the Telegram channel endpoints with no bot to create, no token to manage and no account to log in with.
- Pay per call. Each call is billed on its own, at $0.001 for a page of channel posts and $0.001 for the channel record (Verified 2026-10-16 on the Telegram tools page). Buy calls as you need them: no monthly plan and no minimum top-up. Discovery and inspection are free.
- One install, every API. The same key and the same balance call Telegram and every other tool on Monid. When you want TikTok or YouTube data next, there is no new account (the social media scraping API comparison covers those).
- Lives inside your agent. Install the CLI, add your key, run the prompt above, and the tools are there whenever your agent needs them, with nothing to keep running. Setup is about a minute.
At that price a page of 20 posts costs $0.001 (Verified 2026-10-16), so checking 100 channels once a day is 100 calls, or $0.10.
How do you get the posts of many Telegram channels into one table?
Run the posts endpoint once per channel, keep each response, and flatten the messages arrays into rows. The data comes from the public preview page Telegram publishes for each public channel, so no login is needed and any public channel works.
| Route | What you get | What it takes |
|---|---|---|
| Download a dataset | A snapshot of the channels its author picked | Nothing, but it is a fixed date and a fixed list |
| Export from the Telegram app | Your own chat history | An account that can see the channel, run by hand per chat |
| Write a scraper | Whatever you parse | Parsing, paging and repairs, covered in the next section |
| Monid | Typed JSON for any public channel, one call per page | An install, a key and a username |
For agents
Grab an API key at app.monid.ai, then paste this to your agent and hand it the key:
set up https://monid.ai/SKILL.md
It learns the whole discover, inspect, run workflow itself. More in the agent quickstart.
For humans
npm install -g @monid-ai/cli
monid keys add -k <your-api-key> -l main
Step 1. Check the channel before you read it
Confirm the username resolves and see the size first. The endpoint is tikhub/api/v1/telegram/web/fetch_channel_info, billed per call, and it requires channel.
monid run -p tikhub -e /api/v1/telegram/web/fetch_channel_info \
--query '{"channel": "durov"}'
It returns the title, verification flag, description, photo, subscriber count and three media counters.
Step 2. Pull a page of posts
The endpoint is tikhub/api/v1/telegram/web/fetch_channel_posts, billed per call. It requires channel and takes limit (1 to 100), before and after.
monid run -p tikhub -e /api/v1/telegram/web/fetch_channel_posts \
--query '{"channel": "durov", "limit": 20}'
On 2026-10-16 this returned 20 messages, newest first, with the channel record and a pagination block: before_cursor 531, after_cursor 552, has_more_before true.
Step 3. Walk backwards with the cursor, not with arithmetic
monid run -p tikhub -e /api/v1/telegram/web/fetch_channel_posts \
--query '{"channel": "durov", "limit": 20, "before": 531}'
before takes the before_cursor from the previous response. Do not compute the next id yourself, for the reason in the "what goes wrong" section below.
Step 4. Loop it over a watchlist
Put one username per line in channels.txt, then run:
mkdir -p out
while read -r ch; do
monid run -p tikhub -e /api/v1/telegram/web/fetch_channel_posts \
--query "{\"channel\":\"$ch\",\"limit\":20}" > "out/$ch.json"
done < channels.txt
Each channel writes one file with its latest page. Follow before_cursor only for the channels where one page is not enough; exporting YouTube channel videos to CSV shows the same flatten-to-rows step for another platform.
Or hand the whole job to an agent
Give this to your agent![]()
Set up https://monid.ai/SKILL.md, and then use Monid to pull the last fifty posts from three Telegram channels I follow, parse the view strings into numbers, and show me which posts beat their channel's median.Can you scrape a Telegram channel yourself with Python?
Yes, and for one channel it is an afternoon: request the public preview page, parse the HTML with BeautifulSoup, and follow the older-posts link. An MTProto client such as Telethon is the other route, and reads through a logged-in account.
Parsing the preview page is yours to keep alive: when the markup changes, your job breaks, a pattern Reddit scraping alternatives describes for another platform. Message ids have gaps, so paging by arithmetic fails quietly. Counts are formatted for humans, so every number needs a parser. Media links expire. An account-based client ties your scraping to a real phone number and account.
The rules side is separate: what you may do with public posts depends on where you operate and how you use the data, so read Telegram's terms before you build anything you will sell.
What Monid maintains for you is the part that breaks: the collection, the parsing into typed JSON, the cursors and the pagination block. A page of posts costs $0.001 (Verified 2026-10-16). Set against hours of your own time, the choice is easy: pick Monid for anything you will run more than once, and write your own parser only for a one-off on a single channel.
What does Telegram channel data look like, and what can you build with it?
Two records: the channel and its messages. We ran both on 2026-10-16 against durov, so the fields below are what came back, not what a spec promises.
The channel record
fetch_channel_info returned:
{
"username": "durov",
"title": "Pavel Durov",
"verified": true,
"description": "Founder of Telegram.",
"photo": "https://cdn4.telesco.pe/file/…",
"subscribers": "10.4M",
"counters": { "subscribers": "10.4M", "photos": "102", "videos": "47", "links": "200" }
}
Four counters and a verification flag. photos, videos and links count the media the channel has posted, a rough content mix without pulling a message. Every number is a string.
The message record
fetch_channel_posts returns 15 fields per message. One post, trimmed:
{
"id": 547,
"channel": "durov",
"url": "https://t.me/durov/547",
"type": "text",
"date": "2026-09-06T17:40:39+00:00",
"text": "the plain message body",
"text_html": "the same body with entity markup",
"views": "3.82M",
"author": "Pavel Durov",
"is_forwarded": false,
"forwarded_from": null,
"reply_to": null,
"link_preview": { "url": "https://t.me/contest/460", "site_name": "Telegram", "title": "Telegram Contests", "description": "…" },
"media": { "photos": [], "videos": [], "has_unsupported": true },
"reactions": [ { "emoji": "⭐", "count": "8.52K", "paid": true }, { "emoji": "", "count": "28.6K", "paid": false } ]
}
type was text, video or photo in the 25 posts we pulled, and it tells you whether media will hold anything. Photos come back as addresses, videos as objects with url, thumb and duration.
The two text fields are not duplicates
text is plain and text_html keeps the markup, including the outbound links with their hrefs. Keep the HTML one if you track what a channel links to.
What you can build with it
- A watchlist of channels, ranked by pace. Pull the latest page per channel every day and rank posts by views per day since posting, not by raw views (the next section shows why).
- A link and mention tracker. Parse the hrefs out of
text_htmlto see which sites and channels a channel points to, and when that changes.
What goes wrong when you pull Telegram channel data?
Four things hide until you run more than one channel. All showed up in our 25 posts on 2026-10-16.
Why is the view count a string?
Because the surface renders it for humans, and the rounding happens before you see it. Our posts carried "988K", "1.29M", "3.36M", "6.84M" and "24.4M". "1.29M" is somewhere in a ten-thousand-view window, already gone before the response left the server, and "24.4M" covers a window of a hundred thousand.
A parser is correct and still cannot give you an exact number:
SUFFIX = {"K": 1_000, "M": 1_000_000, "B": 1_000_000_000}
def views(raw):
if not raw: return None
raw = raw.strip()
if raw[-1] in SUFFIX:
return round(float(raw[:-1]) * SUFFIX[raw[-1]])
return int(raw.replace(",", ""))
Use round, not int: 1.89 * 1_000_000 is 1889999.9999999998 in floating point, and int would return 1889999. Store the raw string next to the parsed integer, so a later jump can be traced to the number or to the rounding bucket. The same holds for reactions[].count ("5.62K") and the channel counters.
Why do older posts have more views than newer ones?
Because a Telegram view count is a lifetime total that never resets, so it measures age as much as reach. From the 25 posts, as of 2026-10-16:
| Posted | Views | Age | Views per day |
|---|---|---|---|
| 2026-10-11 | 988K | 5 days | 198K |
| 2026-10-10 | 1.29M | 6 days | 215K |
| 2026-09-11 | 3.36M | 35 days | 96K |
| 2026-08-14 | 6.84M | 63 days | 109K |
| 2026-06-15 | 24.4M | 123 days | 198K |
The raw column runs almost perfectly against recency: the newest post has the smallest number and the oldest has the largest. That is a counter that has run 123 days on one post and 5 on another, not a channel whose reach collapsed. Ranking posts by views ranks them by age.
Divide by age. Views per day since posting is crude and works:
from datetime import datetime, timezone
age = max((datetime.now(timezone.utc) - datetime.fromisoformat(m["date"])).days, 1)
rate = views(m["views"]) / age
On the five rows this reorders the list: 2026-10-10 runs at about 215K a day and 2026-09-11 at about 96K, though the raw numbers say the opposite. For true velocity, sample the same post twice and difference the readings.
Why are message ids missing?
Our first page ran 552, 551, then 548, 547 down to 531: ids 549 and 550 never appeared, so 20 messages spanned 22 id slots. The second page, before: 531 with limit: 5, returned 529, 528, 527, 526 and 525, so id 530 is also absent. The gaps are deleted or non-public messages.
Message ids are a sequence with holes, so before and after are cursors and not offsets. Asking for ids 500 to 520 does not return 20 messages, and a loop that subtracts limit each time will skip or repeat. Pass before_cursor from the response and let has_more_before tell you when to stop.
Why are some fields empty?
In our posts:
reply_towasnullon every row, andlink_previewwasnullon most.- The newest post had
is_forwarded: truewithforwarded_fromset to{ "name": null, "url": null }: the flag is there, the source is not. - Most reactions came back with
emojias an empty string. Only the paid star reaction carried a character, so custom emoji reactions cannot be told apart byemojialone; use the order and thecount. Cursor and count-string quirks like these are also what the TikTok user finder handles. - One video had
url: nulland another hadduration: nullnext to a thumbnail. - There is no forwards or share count among the 15 fields.
Test for null and empty strings on every field you depend on.
Photo and video addresses are signed and expire, so re-host anything you want to keep as soon as you pull it.
Which endpoint should I use for which job?
| Endpoint | What it does | Input | Returns | Latency | Billing |
|---|---|---|---|---|---|
tikhub/api/v1/telegram/web/fetch_channel_info | Channel record | channel | Title, verified flag, subscribers and media counters | About 3 s typical | Per call |
tikhub/api/v1/telegram/web/fetch_channel_posts | A page of posts | channel, limit, before, after | Up to 100 messages, channel record and a cursor block | About 3 s typical | Per call |
Both rows were inspected and run on 2026-10-16; latency is the typical (median) run time. The current price is on monid.ai/tools. Our three runs each billed one unit. The same channel-level logic on another platform is in YouTube scraping past the quota.
Both bill per call, so watching two hundred channels once a day is two hundred calls whatever any of them posted. The posts endpoint already returns the channel record, so the info call is for qualifying a channel before you read it, not for every refresh.
When is another route a better fit?
You administer the channel. If it is yours, Telegram's own analytics for channel admins give you exact numbers rather than rounded strings, plus subscriber growth and traffic sources that never appear on a public preview.
The channel is private or invite-only. A channel with no public preview has nothing here to read.
You need exact numbers. The rounding is a hard floor on resolution. If your analysis turns on differences smaller than a rounding bucket, such as half a percent of growth on a post at "5M", no parser will recover what was discarded before the response was written.
You need a full archive of a chat you are in. Telegram's desktop app exports the history of chats your own account can see, which is the better route for a complete copy.
You want to send messages or read member lists. Nothing here writes, and nothing here lists the people in a channel. This is a read path over public posts.
And the disclosure: we resell these endpoints. The most useful things in this post are free whoever you buy from: divide views by age, store the raw string next to the parsed number, and page with cursors.
Conclusion
The quickest way to get Telegram channel data without a bot token is one posts call per channel through Monid: $0.001 a call (Verified 2026-10-16), one key for Telegram and everything else, about a minute to set up and ready inside your agent whenever you need it. A watchlist of 100 channels is 100 calls, or $0.10 a day. Writing your own parser works for one channel and costs hours to keep alive; Monid keeps the collection maintained.
Two things matter more than the route. Views are rounded strings measuring a lifetime total: parse with round, keep the raw string and divide by age, or your top posts will be your oldest. And ids have holes, so page with before_cursor, never arithmetic.
How we estimated the time saved: your own Telegram channel reader is roughly 2 to 4 hours for fetching and parsing the preview page, 2 to 4 for paging with gaps, 2 to 4 for number parsing and normalisation, and 4 to 8 for the first month of upkeep. That is 10 to 20 hours. The 1 minute is the install, key and first call once you already have a Monid key.
Free next step: run monid inspect -p tikhub -e /api/v1/telegram/web/fetch_channel_posts, make one call on a channel you follow, and print views next to date. The age effect shows up in the first twenty rows.
FAQ
Does this work on private or invite-only Telegram channels?
No. It reads the public preview page, so a private channel, an invite-only channel, or a public channel whose owner disabled the web preview returns nothing to read. The channel record carries exists = false for a channel that does not exist or is not public, and preview_available = false when the preview is switched off.
How far back does a Telegram channel's history go?
As far as the channel has public posts, walked one page at a time with the before cursor, until has_more_before turns false. Each page is one billed call, so deep history on an active channel is a cost in calls and time, not a hard limit.
Can I export the members or subscribers of a Telegram channel?
No, only the count. The channel record returns subscribers as a rounded string, for example "10.4M", and nothing on the public preview lists the people behind it. Reaction counts and views are totals too, not lists of who reacted or who watched.
How do I turn Telegram view counts into numbers?
Strip the suffix and multiply: K is a thousand, M a million, B a billion, then round the result. "1.29M" becomes 1,290,000, but the true count is anywhere in a ten-thousand-view window, so keep the raw string next to the integer and compare only across orders of magnitude.
Published September 2026.

