Telegram Channel Scraper - Posts, Views & Exact Subscribers
Pricing
from $1.83 / 1,000 post returneds
Telegram Channel Scraper - Posts, Views & Exact Subscribers
For OSINT, crypto and market research and channel vetting: posts, views, reactions and forwards from any public Telegram channel, plus the exact subscriber count from the profile page. On one 10.9M channel the rounded preview hid 43,313 people. Median views, ERR and cadence are measured.
Pricing
from $1.83 / 1,000 post returneds
Rating
0.0
(0)
Developer
NeverEmpty
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
17 hours ago
Last modified
Categories
Share
Telegram Channel Scraper - posts, views and the exact subscriber count
For people buying or selling channel advertising, media monitoring and ranking channels: any public Telegram channel read from the pages Telegram serves without a login, returned as two kinds of row — one per post, and one per channel.
The channel row carries the exact subscriber count, which is what the other Telegram scrapers do not give you. Telegram's public preview page shows a rounded figure — Bloomberg's channel reads 172K there — while the channel's own profile page publishes the exact count, 171,899. This Actor reads both, returns both, and puts the difference in its own column. On a large channel the gap is wide enough to matter: Pavel Durov's channel shows 10.9M on the preview and 10,856,687 on the profile — a difference of 43,313 people that a rounded figure hides for weeks at a time.
On top of that, the channel row carries statistics measured from the posts the run actually read — median, mean, highest and lowest views, the top post, median reactions, views per subscriber, posts per day over the window read, the share of posts carrying a photo, a video, a link preview or a forward, and the busiest posting hour in UTC. These are the numbers an advertising buyer asks for, and they are measured here rather than estimated.
A name that is not a public channel is reported as one. Telegram answers the preview URL with a 302 for a bot, a personal account, a group and a channel with no public preview, and answers "no more posts" with a 200 page rather than an error — both are read correctly instead of being passed on as an empty result.
Measured from Apify on 2026-09-07: t.me answered with the full page on 3 of 3 direct requests (145 KB, 217–449 ms), and t.me/robots.txt is a 404 — nothing is declared as disallowed. No API key, no login, no proxy needed. Export as JSON, CSV or Excel.
What one run gives you
Post rows (rowType: "message")
| Column | What it is |
|---|---|
channel, messageId, postUrl | the channel and the post, with its permanent t.me link |
publishedAt | the post time, exactly as Telegram publishes it (UTC, with offset) |
text, textLength | the post text with its line breaks kept |
views, viewsText, viewsAreRounded | the view count as a number, the text Telegram printed, and a flag |
reactionsTotal, reactions[] | each reaction with its emoji or custom emoji id, its count, and whether it is a paid (Stars) reaction |
isForwarded, forwardedFromChannel, forwardedFromUrl, forwardedFromName | where a forwarded post came from, and the link to the original |
authorSignature, isEdited | the signature on signed posts, and whether the post was edited |
hasPhoto, hasVideo, hasLinkPreview, linkPreviewUrl/Title/Site | the attachments this Actor has measured on the public preview |
links[], mentions[], hashtags[] | outgoing links, @channel mentions and hashtags, told apart |
Channel rows (rowType: "channel", one per channel, on by default)
channelTitle, description, verified, subscribers (exact), subscribersDisplay (rounded),
subscribersDisplayValue, subscribersDisplayDiff, photosDisplay, videosDisplay, linksDisplay,
messagesRead, oldestPostAt, newestPostAt, windowDays, postsPerDay, viewsMedian,
viewsMean, viewsMax, viewsMin, topPostUrl, topPostViews, viewsPerSubscriberPct,
reactionsMedian, forwardedPct, withPhotoPct, withVideoPct, withLinkPreviewPct,
busiestHourUtc.
What is measured, and what is not
- View counts are rounded by Telegram, to three significant figures (
24.2M,53.1K). There is no exact figure published anywhere on the public pages, so this Actor does not pretend to have one: every post row carriesviewsAreRounded, and every channel row carriesviewsAreApproximate. The rounding is at most about 0.5% of the value. Reaction counts are printed the same way. - The subscriber count on the profile page is not rounded, and that is the one in
subscribers. If Telegram ever answers with a rounded figure there, the column is left empty rather than filled with a rounded number labelled exact. - Telegram serves 20 posts per page. Reading more pages costs more requests, not more accuracy.
- Photos, videos and link previews are the attachment types measured on the public preview pages. Other kinds are not claimed either way rather than guessed at.
- Invite links (
t.me/+...,t.me/joinchat/...) andt.me/c/...are private entrances. They are rejected rather than read, and no login or account is ever used. - Post text is returned as published, with one exception: email addresses, numbers written with
an international
+prefix, and numbers directly after phone/tel/call/whatsapp/viber are replaced with[email removed]/[phone removed]. Plain long numbers - block heights, transaction amounts, order ids - are left alone, andtextLengthis the length of what you receive. postsPerDayis measured overwindowDays, the span between the oldest and newest post the run read, using the gaps between posts. It needs at least two posts; with one it is empty rather than guessed.busiestHourUtcis empty when two hours tie rather than picking the earlier one.subscribersis filled only when Telegram labels the figure "subscribers". A group that reports "members", or a page that reports "online", leaves it empty rather than passing off a different number as a subscriber count.- A name nobody has taken and a name that exists without a public preview are two different answers, and this Actor tells them apart by asking for the profile page as well - one extra request, so a typo comes back as a typo rather than as "this channel is private".
- One channel can hold several usernames.
t.me/techmemeandt.me/arstechnicaboth lead to the same channel, and the preview page shows whichever name you asked for - so a list containing both looks like two channels. Every row carrieschannel(the name Telegram puts on the posts),inputChannel(what you asked for) andchannelMatchesInput, and a second name for a channel already read in the run comes back as a freeduplicate-channelrow instead of the same posts charged twice.
Monitoring: never pay for the same post twice
Turn monitoringMode on and the Actor remembers the newest post id per channel and, on the next
run, asks Telegram only for posts published after it. Adding a channel to your list does not
re-charge the ones already being watched, because nothing about the list is part of what is
remembered.
Posts that could not be delivered - because the run hit its charge limit - are not marked as returned, so the next run delivers them instead of skipping them.
On a run where a channel has posted nothing new, that channel produces no rows at all - not even
its channel-statistics row - and a single free no-change row says so. Telegram answers such a
request with a 200 page carrying "No posts found" rather than an error, and this Actor reads that as
"nothing new", never as "this channel has no posts".
Monitoring adds a flat access fee of $5, charged once per calendar month (UTC), on the first monitoring run of that month that manages to read at least one channel - a run where every name was mistyped costs nothing. That fee is what pays for the days when the channel posted nothing: those runs return no rows and cost nothing else. Runs with monitoring off never trigger it.
Two things worth knowing before you schedule it:
- What is remembered per channel is the newest post already processed, and that includes posts
your filters dropped. A task with
keywordsand a task without them share that memory, so a post filtered out by one will not be delivered by the other later. - Two runs watching the same channel at the same moment both see the same "last post" and will both return it. Runs watching different channels do not interfere - the memory is stored per channel, not as one shared blob.
Rows that are never charged
When there is nothing to sell, you get a row that says why, and it is free:
status | What happened |
|---|---|
no-such-channel | nobody has taken the name. Telegram answers a free name with its generic download page - no title, no subscriber count - instead of a profile |
not-a-public-channel | the name exists, but has no public post preview: Telegram answers the preview URL with a 302 back to the plain profile. It does that for a bot, a personal account, a group, and a channel whose owner turned the preview off, so this row does not claim which |
no-results | the channel page loaded and Telegram published no posts on it |
blocked | Telegram answered with a bot check instead of the page |
unreadable | the page could not be read; nothing is guessed |
no-change | monitoring mode, and nothing has been posted since the last run |
no-match | posts were read and none matched your filters |
duplicate-channel | the name is another username for a channel already read in this run, so its posts are not returned twice |
budget-reached | the run hit the maximum total charge you set for it and stopped; the row says how many posts were left behind |
A no-such-channel row is never dressed up as an empty channel, and an empty channel is never dressed
up as an error.
Input
| Field | What it does |
|---|---|
channels | the public channels to read, as @durov, durov, https://t.me/durov or a link to a single post |
maxMessagesPerChannel | how many of the most recent posts to read per channel (Telegram serves 20 per page) |
maxMessages | a cap across all channels together, applied after the filters |
includeChannelStats | add the one channel row per channel with the exact subscriber count and the measured statistics |
monitoringMode | return only posts you have not been given before |
resetMonitoringState | forget the remembered post ids and start the history over |
postedWithinDays, minViews, onlyWithMedia, onlyWithLinks, excludeForwarded | filters on the posts |
keywords, keywordMatch, excludeKeywords | keyword filters |
useProxy | switch to a residential proxy and retry if Telegram ever answers with a bot check |
Filters
keywords / keywordMatch / excludeKeywords (searched in the text, channel title, forwarded
source, link preview title and hashtags), postedWithinDays, minViews, onlyWithMedia,
onlyWithLinks, excludeForwarded. Posts whose view count or timestamp cannot be read are kept,
not dropped - a filter never silently empties a result because one column was missing.
Connection
Measured from Apify on 2026-09-07: t.me answered with the full page on 3 of 3 direct requests
(145 KB, 217-449 ms), and t.me/robots.txt is a 404 - nothing is declared as disallowed. So no
proxy is used by default. Turn useProxy on to have the run retry through a proxy if Telegram ever
answers with a bot check; a residential proxy is used when your account has one, and a datacenter
proxy otherwise.
A request for posts newer than the newest one comes back as a 200 page of 18,684 bytes whose
body is "No posts found" rather than an error - which is why monitoring reports no-change there
instead of an empty channel.