Telegram Channel Scraper: Public Posts, Views & Media avatar

Telegram Channel Scraper: Public Posts, Views & Media

Pricing

from $0.30 / 1,000 posts

Go to Apify Store
Telegram Channel Scraper: Public Posts, Views & Media

Telegram Channel Scraper: Public Posts, Views & Media

Scrape public Telegram channels via the t.me web preview: one row per post with text, date, views, media, link previews, polls, reactions, hashtags and links, plus channel info. No login, no API key, no browser. $0.30 per 1,000 posts.

Pricing

from $0.30 / 1,000 posts

Rating

0.0

(0)

Developer

subimpact

subimpact

Maintained by Community

Actor stats

0

Bookmarked

3

Total users

2

Monthly active users

a day ago

Last modified

Share

Read public Telegram channels through their t.me/s/<channel> web preview and get clean rows back: post text, publication time, view counts, media type, photo and video thumbnail URLs, document names, link previews, polls, reactions, hashtags, mentions and outgoing links. One channel-info row per channel (title, description, subscribers, media counters, avatar, verified flag), then one row per post. No login, no API key, no browser, no Telegram app.

Pay only for what you get: $0.30 per 1,000 posts and $1.00 per 1,000 channel-info rows. A default run over one channel (50 posts plus its info row) costs about $0.016, plus Apify platform usage.

What you get

  • One row per post, newest first: postId, postUrl, postedAt, text (line breaks kept, HTML stripped), views as an integer plus the viewsText Telegram printed ("5.84M" becomes 5840000).
  • Media without downloading it: mediaType (photo, video, document, audio, voice, sticker, poll, mixed, none), photoUrls, videoThumbUrls, videoDurationSec, documentNames.
  • Rich post details: linkPreview, poll with option percentages, reactions, hashtags, mentions, links, replyToPostId, isForwarded plus forwardedFrom, authorSignature, isEdited.
  • Channel info row: description, subscribers, photosCount, videosCount, linksCount, filesCount, avatarUrl, isVerified, channelUrl.
  • Filters that save money: maxPostsPerChannel, maxTotalPosts, postedAfter, postedBefore, and Telegram's own in-channel search via searchQuery.
  • Delta mode (onlyNew) for schedules: each run delivers only posts newer than the highest post id already delivered for that channel. The cursor lives in a key-value store in your own Apify account.
  • Single post URLs: give https://t.me/durov/531 and you get that post only.

Every run also writes a RUN_SUMMARY record to the run's key-value store: per-channel status, rows, requests and any problem, so a schedule can be checked without reading logs.

Quick start

Input that works exactly as written:

{
"channels": ["durov", "telegram"],
"maxPostsPerChannel": 50,
"includeChannelInfo": true
}

Channel entries may be written as durov, @durov, t.me/durov, https://t.me/durov, https://t.me/s/durov, or a single post such as https://t.me/durov/531.

A monitoring run for one channel, new posts only:

{
"channels": ["telegram"],
"onlyNew": true,
"includeChannelInfo": false,
"maxPostsPerChannel": 100
}

Search inside a channel and keep one week of posts:

{
"channels": ["durov"],
"searchQuery": "Telegram",
"postedAfter": "2026-10-18",
"includeChannelInfo": false
}

Output example

A post row from t.me/s/durov (CDN image URLs shortened here for readability):

{
"recordType": "post",
"channel": "durov",
"channelTitle": "Pavel Durov",
"postId": 531,
"postUrl": "https://t.me/durov/531",
"postedAt": "2026-07-16T20:45:25.000Z",
"isEdited": false,
"editedAt": null,
"text": "🩵 Telegram now has a Rich Text Editor.\n\nIt supports tables, headings, inline media, lists, AI content, formulas, and more.\n\n😈 Messaging apps will never be the same!",
"views": 5840000,
"viewsText": "5.84M",
"authorSignature": "Pavel Durov",
"isForwarded": false,
"forwardedFrom": null,
"replyToPostId": null,
"mediaType": "video",
"photoUrls": [],
"videoThumbUrls": ["https://cdn4.telesco.pe/file/JcEMS9Bq90aZQ4T4hTjXv8G...jpg"],
"videoDurationSec": null,
"documentNames": [],
"linkPreview": null,
"poll": null,
"reactions": [
{ "emoji": "stars", "count": 6300 },
{ "emoji": "emoji-id:5265077361648368841", "count": 54600 }
],
"hashtags": [],
"mentions": [],
"links": [],
"scrapedAt": "2026-10-25T07:49:34.378Z"
}

The matching channel row:

{
"recordType": "channel",
"channel": "durov",
"channelTitle": "Pavel Durov",
"description": "Founder of Telegram.",
"subscribers": 10300000,
"photosCount": 102,
"videosCount": 47,
"linksCount": 200,
"filesCount": null,
"avatarUrl": "https://cdn4.telesco.pe/file/enJjZA2XzVbFAjeTOqFmqCmKVB5C...jpg",
"isVerified": true,
"channelUrl": "https://t.me/durov",
"scrapedAt": "2026-10-25T07:49:34.378Z"
}

A poll row reads like this (mediaType is poll, question and percentages as Telegram shows them):

{
"recordType": "post",
"channel": "polldemo",
"postId": 101,
"postedAt": "2026-10-20T09:15:00.000Z",
"views": 18400,
"mediaType": "poll",
"poll": {
"question": "Which Telegram app do you use most?",
"options": [
{ "text": "Mobile", "percent": 52 },
{ "text": "Desktop", "percent": 31 },
{ "text": "Web", "percent": 17 }
]
}
}

Pricing

Pay per event, charged only after the row is in the dataset:

EventPriceCharged when
post$0.0003 per post ($0.30 per 1,000)a post row was pushed
channel-info$0.001 per channel ($1.00 per 1,000)a channel-info row was pushed
apify-actor-start$0.00005 per runthe run starts (platform event)

Buyer pays Apify platform usage separately. Empty channels, search results with no matches, preview-disabled channels and failed requests cost nothing: no row, no charge. Turn includeChannelInfo off and you pay only for posts.

Typical costs: 500 posts from one channel with channel info = 500 x $0.0003 + $0.001 = $0.151. A scheduled hourly onlyNew run that finds 3 posts = $0.0009.

How this compares

Free-plan list prices on the Apify Store, checked 25 October 2026. Competitor platform usage is charged on top by their listings; check the individual listing, prices change.

ActorStart feePer 1,000 messagesPer 1,000 channel infosUsers on the listing
telegram-channel-scraper (this actor)$0.00005 platform start$0.30$1.00new
automation-lab/telegram-scraper$0.005$1.00$2.00189 in 30 days
khadinakbar/telegram-channel-scraper$0.003$2.00not listed61
tugelbay/telegram-posts-scrapernone listed$2.00not listed27

What is different here beyond the price:

  • Rows as they are ready: every post row is pushed and charged the moment it is parsed, so a run that hits its time limit still delivers everything it collected.
  • Caps that hold: maxPostsPerChannel plus a global maxTotalPosts stop a run before it surprises you.
  • Delta mode built in: onlyNew keeps a per-channel post-id cursor in your own key-value store, and never moves the cursor backwards after a failed page.
  • Per-channel status record: RUN_SUMMARY says which channel was ok, empty, not found, or had its web preview disabled, and how many requests it took.

Limits and honest notes

  • Public channels with the web preview enabled only. Private groups, private channels (t.me/c/...), invite links (t.me/+...) and channels whose owner disabled the preview cannot be read. They come back as preview_unavailable or not_found in RUN_SUMMARY, with no row and no charge. Telegram groups show no web preview at all.
  • Telegram serves 20 posts per page. The actor pages with ?before=<post id> and pauses 300 to 800 ms between pages of the same channel. maxPostsPerChannel is a cap, not a promise: a channel with fewer posts returns fewer.
  • Counts are a snapshot. views, subscribers, reactions and poll percentages are what Telegram printed at scrape time.
  • editedAt is always null: Telegram marks a post as edited (isEdited: true) but never prints the edit time on the public preview.
  • forwardedFrom can be null even when isForwarded is true: Telegram hides the source name for forwards from private or hidden sources.
  • Media are links, not files. Photo URLs and video thumbnails are the CDN links from the page, and Telegram's CDN links can expire. Nothing is downloaded.
  • Animated GIFs are rendered by Telegram's preview as muted video loops, so they arrive as mediaType: "video".
  • In-channel search is Telegram's own: it matches post text, results are ordered oldest to newest, and paging uses the same before= parameter. It is case-insensitive but not a full-text engine over the whole archive. A single post URL returns that post, searchQuery applies to channel timelines only.
  • Reaction glyphs: Telegram prints custom emoji as an image with an id, so such reactions carry emoji: "emoji-id:<id>"; paid star reactions are reported as "stars".
  • One post-id watermark per channel for onlyNew. If you also use searchQuery with onlyNew, the cursor is shared with the timeline run of that channel; use a separate stateStoreName to keep them apart.
  • Direct requests by default. Ten parallel direct requests to t.me answered fine when this actor was built. Enable Apify proxy if your runs get rate limited; a proxy failure fails the request, it never falls back to a direct one.

Responsible use

This actor reads the same pages any browser sees on t.me, for public channels only. Only collect channels you have a reason to collect. Post text can contain personal data: how you store, process and share it is your responsibility under the GDPR, PDPA and any other law that applies to you. Do not use it to build profiles of private individuals or to evade Telegram's rate limits.

Development

npm ci
npm test # node:test, parses the saved t.me fixtures
npm run build

Fixtures in test/fixtures/ were saved from live t.me pages on 25 October 2026 (tokens and CDN file names scrubbed). docs/PARSING.md lists the selectors the parser relies on.