Telegram Channel Scraper: Posts, Comments & Media
Pricing
from $0.07 / 1,000 posts
Telegram Channel Scraper: Posts, Comments & Media
Scrape public Telegram channels without login: posts, views, reactions, media, links, comments, channel details. Search inside a channel and get only new posts for n8n or Make. Export to JSON, CSV or Excel.
Pricing
from $0.07 / 1,000 posts
Rating
0.0
(0)
Developer
Nice Dev
Maintained by CommunityActor stats
0
Bookmarked
7
Total users
3
Monthly active users
37 minutes ago
Last modified
Categories
Share
🔎 What is Telegram Channel Scraper?
Telegram Channel Scraper extracts posts from public Telegram channels (t.me): text, date, views, reactions, photos, videos, links, forwards, polls, plus the comments of each post and the details of the channel when you ask for them. It works as a Telegram API alternative for public channels: no account, no API key, no phone number. Run it on a schedule, call it from your code, or plug it into Make, Zapier or n8n.
Type the channel names (durov, telegram), click Start, and download the posts in JSON, CSV or Excel. Add a keyword to search inside each channel, or tick Only new posts to get, at each scheduled run, only the posts published since the last one. Speed: about 1,000 posts of one channel in 4 minutes with the included proxy (several channels are read side by side), and about 5 times faster without a proxy.
📋 What data can you extract from Telegram?
One item per post, comment or channel, 56 fields:
| Category | What you get |
|---|---|
| 📝 Post | text (plain, HTML and Markdown), publication date, edited mark, link, post number |
| 👀 Reach | views, every reaction with its emoji and count, reactions paid with Stars |
| 🖼️ Media | photo links, videos (thumbnail and duration), documents, audio files, polls, link cards, albums as one row |
| 🔗 Links and mentions | every link, hashtag, @mention, e-mail address and inline button of a post |
| ↪️ Forwards and replies | where a post was forwarded from, which message it replies to |
| 📣 Channel | title, username, numeric id, subscribers, verified badge, SCAM / FAKE label |
| 💬 Comments | author, text, date, reactions and reply-to of each public comment, with the commented post |
| 🧾 Channel details | exact subscriber count, description, photo, counts of photos, videos, files and links, last post date |
| 🔍 Search | the keyword that found a post |
Every field, with an example, is listed in the Output section below. Comments, channel details, e-mail addresses and saved media files are options: they are empty (or absent) unless you tick them.
✅ Why use Telegram Channel Scraper?
- 🔍 Search inside the channels: the keyword is searched by Telegram in each channel, older posts included, not only the latest ones.
- 🔔 Monitoring built in: tick Only new posts, schedule the Actor, and each run reads each channel only from the last post it delivered. Posts already delivered are not read again and not charged.
- 💬 Comments without an account: the public comments of each post, one row per comment, up to 1,000 per post (author, text, date, reactions, the comment it answers).
- 🧾 A row for every channel it cannot read: a closed, hidden, unknown or group channel gives a row that says why, never an empty run with no explanation.
- 🗂️ Many channels in one run: up to 1 000 channels, with a cap per channel so that a big one cannot use up the whole budget.
- 🔌 API, scheduling, monitoring, integrations (Make, Zapier, n8n, Google Sheets…), proxy and JSON/CSV/Excel export via the Apify platform.
🚀 How to scrape Telegram channels
- Create a free Apify account.
- Open Telegram Channel Scraper and list the Channels (
durov,@telegram,t.me/telegram, or a full link). - Optional: a Search inside the channels keyword, a date range, the options you want (comments, channel details…).
- Set Max posts (100 by default, 0 = no limit), then click Start.
- Download the dataset in JSON, CSV, Excel or via API.
💰 How much does it cost to scrape Telegram?
This Actor uses pay per event pricing: you pay for each post saved, plus a small fee per run start. The options are charged only when you tick them: each comment, each channel detail row, each page of comments read, each e-mail address found and each media file saved. The exact prices are in the Pricing tab of the Actor. A run that saves nothing costs only the run start, plus the small fee for each post a filter drops if you use filters (see Pricing).
⚙️ Input
Channels, a cap, and nothing else:
{"channels": ["durov", "telegram"],"maxItems": 100}
Search a keyword inside a channel, from a date:
{"channels": ["durov"],"query": "privacy","postedAfter": "2026-01-01","maxItems": 50}
Monitoring: only the posts published since the last run, one memory per schedule:
{"channels": ["durov", "telegram"],"onlyNew": true,"stateKey": "crypto-news","maxItems": 0}
With links, comments and channel details:
{"startUrls": [{ "url": "https://t.me/s/durov?q=privacy" }, { "url": "https://t.me/durov/427" }],"includeChannelInfo": true,"includeComments": true,"maxCommentsPerPost": 20,"maxItems": 20}
| Field | Notes |
|---|---|
channels | Public channels, in any form: durov, @durov, t.me/durov, https://t.me/s/durov. A link of a channel page keeps its keyword and its page (https://t.me/s/durov?q=privacy), as in startUrls. Max 1 000 channels. A public group gives its details only. |
startUrls | Channel pages, searches inside a channel (https://t.me/s/durov?q=privacy), single posts (https://t.me/durov/427), or a channel read from a post number (https://t.me/s/durov?before=1000). Max 1 000 URLs. |
query, searchQueries | Keyword searched inside each channel, as the channel's own search box does (privacy); searchQueries adds more keywords: channels × keywords = one search each (max 500 searches per run). |
maxItems, maxItemsPerQuery | Posts saved for the whole run (100 by default, 0 = unlimited) and for each channel and keyword (0 = no cap). Comments and channel rows are not counted. |
includeChannelInfo, channelInfoOnly | One row per channel with its exact subscribers, description and counts; the second one returns only these rows, no post. Paid options, off by default. |
includeComments, maxCommentsPerPost | The most recent public comments of each post whose discussion is open, one row per comment (the newest ones, written in the order they were posted), up to 1,000 per post (Telegram shows 100 per page, more are loaded 50 at a time). Paid option, off by default. |
includeEmails, downloadMedia | E-mail addresses written in the posts and comments; photos and video thumbnails saved in the run's key-value store, their links in mediaFiles (they work as long as the run's storage is kept: the data retention of your plan). Paid options, off by default. |
postedAfter, postedBefore | Publication date range: 2026-09-01, or a period before now (7 days, 2 weeks, 30 days; via the API also 24 hours or a full ISO date-time). A channel is read from the newest post back and stops at the first one too old. |
minViews, maxViews, minReactions | Keep the posts seen at least / at most so many times, or with at least so many reactions (0 = no bound). |
mediaOnly, withTextOnly, withLinksOnly, includeForwarded, includeServiceMessages | Keep only the posts with any media (photo, video, file, audio, poll, sticker, location, or a post Telegram shows only in the app; use Only these media types to keep only some), with text, with a link; drop the forwarded posts; add the service messages (channel created, post pinned…). |
mediaTypes | Keep only the posts holding one of these media kinds (photo, video, document, audio, poll, sticker, location). |
includeKeywords, excludeKeywords | Keep only the posts containing one of these words, or drop those that do (sale); case and accents ignored. |
onlyNew, stateKey, resetState | Monitoring: each channel is read from the last post a previous run delivered under this memory key (crypto-news); resetState forgets the memory. |
| Advanced | proxyConfiguration (Apify proxy by default, included in the price; the residential proxy is not available; for a proxy country, US works), maxConcurrency, maxRequestsPerMinute, minRequestIntervalMs, maxRequestRetries, debugLog. |
📦 Output
A post (shortened: the full row has 56 fields, the ones that do not apply are null or empty):
{"type": "post","id": "durov/427","url": "https://t.me/durov/427","channel": "durov","channelTitle": "Pavel Durov","channelUrl": "https://t.me/durov","channelId": 1006503122,"channelSubscribers": 10600000,"channelVerified": true,"channelLabels": [],"postId": 427,"publishedAt": "2026-09-30T14:02:11.000Z","edited": false,"text": "Telegram now has 1 billion monthly users.","views": 18900000,"reactions": [{ "emoji": "👍", "emojiId": null, "count": 15400, "paid": false }],"reactionsCount": 52300,"photos": ["https://cdn4.telesco.pe/file/abc.jpg"],"mediaTypes": ["photo"],"mediaCount": 1,"links": ["https://telegram.org/blog"],"hashtags": [],"mentions": [],"searchQuery": null,"scrapedAt": "2026-10-07T12:00:00.000Z"}
You can download the dataset in various formats such as JSON, HTML, CSV or Excel. A comment row and a channel row have the same columns; type tells them apart.
All 56 fields
| Fields | What you get |
|---|---|
type, id, url | post, comment or channel; a unique row id (durov/427); the public link |
channel, channelTitle, channelUrl, channelId | username, title, link, numeric id of the channel |
channelSubscribers, channelVerified, channelLabels | subscribers (rounded by Telegram on a post, exact on a channel row, empty on a post pasted by its link), verified badge, SCAM / FAKE label |
postId, publishedAt, edited, serviceAction | post number, ISO date, edited mark, what a service message says |
text, textHtml, textMarkdown | the text, with its links and formatting |
views, reactions, reactionsCount, paidStars | views, each reaction with its count, their total, reactions paid with Stars |
author, authorUrl, authorPhoto | signature of a signed post, or the comment author and profile |
forwardedFrom, replyTo | origin of a forwarded post, the message a post or comment replies to |
photos, videos, documents, audio | media of the post |
poll, linkPreview, buttons | poll question and results (no results on a post pasted by its link: its page shows none), link card, inline buttons |
mediaTypes, mediaCount, albumPostIds, mediaFiles | kinds of media, how many, post numbers of an album, links of the files saved by Download media |
links, hashtags, mentions, emails | every link, hashtag, @mention and e-mail address of the text |
commentsCount, relatedPostUrl | comments of a post (0 = discussion closed); for a comment, the post it belongs to |
channelDescription, channelPhoto, isGroup, membersOnline | channel and group rows: description, photo, group or channel, members online |
photosCount, videosCount, filesCount, linksCount | channel rows: counts of what the channel published |
webPreview, lastPostId, lastPostAt | channel rows: open, closed, not_found or group; the newest post and its date |
searchQuery, scrapedAt | the keyword that found the post; ISO timestamp of the extraction |
💡 Tips
How to get more results
Set maxItems to 0 and maxItemsPerQuery to the number of posts you want from each channel. A channel is read from its newest post back, page after page, with no limit on its history.
How to reduce costs
The price is per post, so the levers are maxItems, maxItemsPerQuery, the date range (postedAfter stops the reading of a channel at the first post too old), the filters, and onlyNew for recurring runs (you never pay twice for the same post). Leave the options you do not need unticked.
Search inside a channel
Fill query (and searchQueries for several keywords): Telegram searches each channel and the Actor reads only the matching posts, however old. Each post carries the keyword that found it in searchQuery.
Several searches in one run
Fill channels and searchQueries: the Actor runs one search per channel × keyword (3 keywords × 4 channels = 12 searches, up to 500 per run). A post found by several keywords is saved — and charged — once. Set maxItemsPerQuery to give every channel its own cap: without it the first channels can use up the whole maxItems.
Monitoring: only the new posts
Tick Only new posts (onlyNew) and schedule the Actor. The first run returns the posts allowed by the caps and dates; each later run reads each channel only from the last post it delivered, so a delivered post is never read, saved or charged twice. The memory lives in a named key-value store of your account (telegram-channel-scraper-seen, up to 150,000 posts per key) and is only updated with posts that really reached the dataset: a post you paste by its link, or a page you paste with ?before= / ?after=, does not move where its channel stopped, and a run that was stopped before its end (its maximum cost, a site that changed) leaves the memory under the first post it did not deliver, so the next run delivers it. A post that minViews or minReactions dropped while it was among the newest (its counters can still grow) is checked again by the next run, with the filter fee, until it passes or a newer post is delivered. Give each schedule its own stateKey.
Comments
Tick Comments to get the public comments of each post whose discussion is open. A channel without comments is detected after a few posts and no more comment pages are asked for it.
🔌 Integrations and API
Call the Actor via the Apify API, the JavaScript or Python clients, or connect it with integrations and webhooks (Make, Zapier, n8n, Google Sheets, Slack, Airtable…). The dataset can be fetched as JSON or CSV from any tool.
🤖 Use with AI agents (MCP)
AI agents (Claude, ChatGPT, Cursor…) can find and run this Actor through the Apify MCP server, billed to their Apify account like any run. It returns one item per Telegram post. Actor id: nice_dev/telegram-channel-scraper; MCP server with this Actor only: https://mcp.apify.com/?tools=fetch-actor-details,nice_dev/telegram-channel-scraper.
Smallest input, for a cheap first call:
{"channels": ["durov"],"maxItems": 10}
Key output fields: channel, postId, publishedAt, text, views, reactionsCount, url.
Cost: see the pricing section above. Cap each call with maxItems and, through the API, with the run option maxTotalChargeUsd.
❓ FAQ
Is it legal to scrape Telegram?
The Actor only reads what Telegram shows publicly to any anonymous visitor on the web: the posts of public channels. It logs in to nothing. Posts and comments can contain personal data, which is protected by GDPR: do not store it without a legitimate reason. You are responsible for using the data in compliance with Telegram's Terms of Service and applicable law. This Actor is not affiliated with Telegram.
Does it need a login or a proxy?
No login. The proxy is included in the price: leave the default setting (the residential proxy is not available). Some channels are hidden on the web in some countries: pick another proxy country for them — US works; a country where Apify Proxy has no IP fails the run, with a message that says so. About 5 times faster without a proxy (untick Apify Proxy), but then a request Telegram turns away is asked again from the same address only, after a pause. A request Telegram turns away is retried at once on a new proxy session, up to 10 times on top of the retries (without a proxy, after a pause of 5 seconds, doubled at each retry up to 150 seconds).
Why does a channel give a row and no post?
A channel row with webPreview set to closed means the channel hides its posts on the web (some channels only show them in the app), not_found that the name belongs to nobody, group that it is a public group (its messages are not published on the web, only its details). These rows are free unless you ticked Channel details.
Is the data safe to open in Excel or to show on a web page?
Texts are the channels' own words, copied as they are. A text can begin with -, +, = or @: Excel and Google Sheets may read such a cell of a CSV file as a formula or as a number. The Actor leaves the text as it is, so that the JSON and the API give the real value: when you open a CSV, import these columns as text. On a web page, escape the text: textHtml is Telegram's own markup and the Actor does not sanitize it.
Known limitations
- Only public channels whose web preview is open give posts; public groups give their details only.
- Views, reactions and subscribers of a post are rounded by Telegram (
10.6M); the exact subscriber count is on the channel row. - Photo and video links of Telegram expire: tick Download media to save the files in the run's key-value store, where their links work as long as the run's storage is kept (the data retention of your plan): copy the files elsewhere to keep them for good.
onlyNewremembers post numbers, not their content: a post that was edited is not returned again.- Two runs sharing the same
stateKeyat the same time may both return the same new post. - Comments: the most recent ones of each post, up to Max comments per post (1,000 at most).
A run that reaches its timeout stops itself about 45 seconds before it: no new page is asked, what it read is saved and, with onlyNew, remembered, and the run ends Succeeded with "Stopped before the run's timeout". Resurrect it to go on from there, or give the next run a longer timeout (Run options).
A run the platform stops without warning (out of memory)
- Resurrect it: it goes on from where it stood at most a minute before the stop. What it had read since is read again, and the posts already saved are skipped: none is delivered or charged twice, and
maxItemsstill counts them. - With
onlyNew, the memory is saved after each write (at most once every 2 seconds): resurrect the stopped run and the posts it had saved meanwhile join the memory; leave it stopped for good, and the next run may return the posts of its last 2 seconds once more.
Something doesn't work?
The last line of the log counts the posts saved, those filtered out and the requests that failed after every retry. Those requests are listed, with the reason, in the FAILED_REQUESTS record of the run's key-value store. A run that saved nothing and had failed requests fails, and its last message gives the reason.
If Telegram changes its pages, you are told instead of paying for blank rows. If the first 20 posts read all lack their date, channel title or view count, the run saves nothing more, stops and fails, and its last message names the missing field: at most those first posts are charged. A post that postedAfter / postedBefore drops because it has no date at all counts among those 20. A run of fewer posts (a scheduled onlyNew run that finds a few new ones, a small Max posts) is checked at its end, from 2 posts (the view count from 5): its posts are already saved, and the run fails with the missing field instead of ending green.
🛟 Support
Open an issue in the Issues tab with a link to your run: the run log and the FAILED_REQUESTS record of the key-value store show exactly which URLs failed and why.