Telegram Channel Scraper: Messages, Views, Media, No Login
Pricing
from $2.00 / 1,000 results
Telegram Channel Scraper: Messages, Views, Media, No Login
Scrape messages from public Telegram channels with no login, phone number or API key. Export posts with text, date, views, reactions, media links, polls, replies and forward sources, plus subscriber counts. Keyword and date filters for OSINT, news and crypto monitoring.
Pricing
from $2.00 / 1,000 results
Rating
0.0
(0)
Developer
Michal Pšenčík
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
17 days ago
Last modified
Categories
Share
Telegram Channel Scraper exports the messages of any public Telegram channel to JSON, CSV or Excel. For every post you get the text, the exact posting time in UTC, the view count, reactions, photo, video and voice-note links, poll results, the post it replies to, the channel it was forwarded from, and a link back to the post. Each channel also gets one record with its title, description and subscriber count.
No Telegram account, no phone number, no API key, no api_id, no bot token. The Actor reads
Telegram's own public web preview at t.me/s/<channel>, the page anyone can open in a browser, so there
is nothing to log in to, no session file to keep alive and no account to get banned.
Try it now: leave the Input tab at its defaults and press Start to get the latest posts from
@telegram and @durov in a few seconds.
Why use this Telegram scraper?
- Zero credentials. Paste channel usernames or
t.melinks and run. Nothing to register at my.telegram.org, no SIM, no 2FA. - $2 per 1,000 posts, platform usage included. Plus $0.005 per run. No subscription, no rental, no separate compute bill. See pricing for worked examples.
- Pay only for matching posts. The keyword filter runs before anything is saved, so a monitoring run over thousands of messages bills only the handful that mention your terms.
- Everything the public preview shows. Views as integers, reactions with counts (custom emoji and paid Telegram Stars included), poll questions with vote shares, reply chains, forward sources, link preview cards, file names and sizes, author signatures and the edited flag.
- Only new posts on a schedule. Turn on
onlyNewPostsand each scheduled run returns, and bills, only the posts published since the previous one. - Private channels handled cleanly. A channel without a public preview is reported in the log and the run's status message and skipped; the rest of the run carries on.
- Stable keys for reruns.
postId(channel/messageId) never changes, so scheduled runs upsert cleanly and you can track a post's views over time.
What data can you extract from Telegram?
| Field | Example | What it is |
|---|---|---|
channel | durov | Channel username, without the @ |
messageId | 546 | Telegram's post number inside the channel |
postId | durov/546 | Unique, stable key for the post |
url | https://t.me/durov/546 | Link to the post |
date | 2026-08-31T16:30:15.000Z | Posting time, ISO 8601 in UTC |
text | Gram Wallet in Telegram… | Full post text with line breaks and emoji |
views | 992000 | View count as a number (viewsText keeps the 992K shorthand) |
reactions | [{ "emoji": "⭐", … }] | Each reaction with its count |
media | [{ "type": "video", … }] | Photos, videos, round videos, voice notes, files and stickers |
poll | { "question": …, … } | Poll question, type, voter count and each option's percentage |
replyTo | { "messageId": 123066, …} | The post this one replies to |
forwardedFrom | { "channel": "luxta_tv" } | The channel a forwarded post came from |
linkPreview | { "title": …, … } | The link preview card under the post |
outlinks | ["https://…"] | Every link in the post text |
subscribers | 10900000 | On the channel record: subscriber count (plus photo, video, link counts) |
The full field reference is further down.
Use cases
- OSINT and investigations. Archive what a set of channels published, with exact timestamps, view counts, forward sources and reply chains to map who amplifies whom.
- Brand, news and competitor monitoring. Run it on a schedule with a keyword filter to catch every mention of a brand, product, ticker or place across many channels, and push the hits to Slack, Google Sheets or a webhook.
- Crypto and trading signals. Collect calls and announcements from signal and project channels, with their timing and reach, straight into a spreadsheet or database.
- Media and audience research. Compare channels by subscribers, posting rhythm, views and reactions.
- Research datasets and AI pipelines. Page back through a channel's history with a date cut-off and feed clean text into sentiment analysis, translation, summarisation or a RAG index.
How to scrape a Telegram channel
- Click Try for free (or open the Actor in Apify Console).
- In Channels, add the channels you want.
durov,@durov,https://t.me/durovandhttps://t.me/s/durovall work. - Set Maximum messages per channel. The default is 40, two pages of the preview.
- Optionally add a Keyword filter, or a date in Only messages posted since.
- Press Start. Forty messages from two channels take a few seconds.
- Open the Output tab and download the data as JSON, CSV, Excel, HTML or XML, or read it through the Apify API.
To keep the data fresh, attach a Schedule in Apify Console: every few minutes for a monitoring feed, or once a morning for a daily digest. Turn on Only new posts since the last run so each scheduled run saves, and charges, only the posts published since the previous one.
Input
All fields are optional; the defaults return the latest 40 posts from @telegram and @durov.
| Field | Type | Default | Description |
|---|---|---|---|
channels | array | ["telegram", "durov"] | Channels to scrape. A username, an @username or any t.me link. |
maxItems | integer | 40 | Messages to return per channel, newest first. Without keywords it is the only size limit. 0 means no limit. |
keywords | array | [] | Only return messages whose text contains one of these words or phrases, matched case-insensitively. |
since | string | empty | Skip messages older than this date and stop paging back at it. YYYY-MM-DD or a full ISO 8601 timestamp. |
onlyNewPosts | boolean | false | Remember each channel's newest post and, on later runs, return only posts published since. For scheduled monitoring. See the FAQ. |
maxScannedMessages | integer | 500 | Keyword runs only: messages read per channel, matching or not, before giving up on finding more matches. Ignored without keywords. 0 means no limit. |
proxyConfiguration | object | Apify proxy off | Optional. The preview serves these pages without an anti-bot challenge, so datacenter proxies are plenty if you want one. |
Latest posts from a few channels:
{"channels": ["telegram", "durov", "https://t.me/nexta_live"],"maxItems": 100}
Keyword monitoring across channels, reading up to 1,000 recent posts in each:
{"channels": ["nexta_live", "durov"],"keywords": ["bitcoin", "airdrop", "wallet"],"maxItems": 50,"maxScannedMessages": 1000}
A full backfill since a date:
{"channels": ["durov"],"since": "2026-01-01","maxItems": 0}
A scheduled monitor that saves only posts published since its previous run:
{"channels": ["nexta_live", "durov"],"maxItems": 200,"onlyNewPosts": true}
Output
Each post is one dataset item with "type": "message". Each channel adds one item with
"type": "channel" before its messages. Filter on type if you only want one of them. The examples below
come from real runs.
The channel record:
{"type": "channel","channel": "durov","title": "Pavel Durov","description": "Founder of Telegram.","url": "https://t.me/durov","imageUrl": "https://cdn4.telesco.pe/file/HYnMQg4YKLOXAKQEfmxf0NzfSxGdMvCScrzLMtLj6Mx…","subscribers": 10900000,"subscribersText": "10.9M","photosCount": 102,"videosCount": 46,"filesCount": null,"linksCount": 198,"scrapedAt": "2026-09-03T17:02:12.041Z"}
A post with a link preview:
{"type": "message","channel": "telegram","messageId": 460,"postId": "telegram/460","url": "https://t.me/telegram/460","date": "2026-08-26T19:12:34.000Z","text": "For all the info from today's update and a look back at 13 years of Telegram features — check out our blog:\nhttps://telegram.org/blog/welcome-messages-buttons-TG-13\n\nAugust Features\n1 • 2 • 3 • 4 • 5 • More","views": 843000,"viewsText": "843K","forwardedFrom": null,"replyTo": null,"media": [],"linkPreview": {"url": "https://telegram.org/blog/welcome-messages-buttons-TG-13","siteName": "Telegram","title": "Welcome Messages, Buttons in Messages and Signed Gifts","description": "Introducing Welcome Messages to greet new members of groups or channels, Buttons in Messages to make any text interactive, Inline Documents in Messages and much more.","imageUrl": "https://cdn4.telesco.pe/file/dhX3eCd_S2LrqYN1CQrGUhmYQarf3dPyUfR0Z_uOtu6…"},"outlinks": ["https://telegram.org/blog/welcome-messages-buttons-TG-13", "https://t.me/telegram/455"],"reactions": [],"poll": null,"authorSignature": null,"edited": false,"scrapedAt": "2026-09-03T17:02:11.938Z"}
A poll comes back with its options and the share of the vote each one holds:
{"type": "message","channel": "polls","messageId": 122,"url": "https://t.me/polls/122","date": "2026-09-03T08:00:15.000Z","text": "","views": 8,"poll": {"question": "What's the most realistic path for China-West relations over the next decade?","type": "Anonymous Poll","voters": 1,"options": [{ "text": "Managed rivalry with guardrails", "percent": 0 },{ "text": "Full economic decoupling", "percent": 0 },{ "text": "Gradual cooperation on shared crises", "percent": 100 },{ "text": "Escalating conflict with no resolution", "percent": 0 }]}}
A reply carries the post it answers, a forward carries its source, files come back as a name and a size, and reactions carry their counts:
{"replyTo": {"messageId": 123066,"url": "https://t.me/nexta_live/123066","author": "NEXTA Live","text": "Россияне атаковали университет в центре Киева — в это время у студентов шли занятия…"},"forwardedFrom": { "name": "LUXTA", "channel": "luxta_tv", "url": "https://t.me/luxta_tv/8235" },"media": [{ "type": "document", "url": null, "fileName": "Конкретная математика.zip", "fileSize": "15.4 MB" }],"reactions": [{ "emoji": "🤬", "emojiId": null, "count": 1280 },{ "emoji": "😢", "emojiId": null, "count": 173 }]}
CDN links above are shortened with … for readability; the real values are full URLs.
Data fields
| Field | Type | Description |
|---|---|---|
type | string | message or channel. |
channel | string | Channel username, without the @. |
messageId | number | Telegram's post number inside the channel. Stable, so use channel + messageId as your key. |
postId | string | <channel>/<messageId>, the single-field version of the same key. |
url | string | Link to the post on t.me. |
date | string | null | When it was posted, ISO 8601 in UTC. |
text | string | Post text with line breaks preserved and emoji intact. Empty for media-only posts. |
views | number | null | View count, expanded from the preview's 843K shorthand. |
viewsText | string | null | The shorthand as the preview renders it. |
forwardedFrom | object | null | { name, channel, url } for a forwarded post. channel and url are null for a private source. |
replyTo | object | null | { messageId, url, author, text } of the post being replied to. |
media | array | One entry per attachment: { type, url, thumbnailUrl, duration, fileName, fileSize }. |
linkPreview | object | null | The preview card: { url, siteName, title, description, imageUrl }. |
outlinks | array | Every http(s) link inside the post text, deduplicated. |
reactions | array | { emoji, emojiId, count } per reaction. Custom emoji have an id and no character. |
poll | object | null | { question, type, voters, options[] }, each option with its text and percent. |
authorSignature | string | null | The signature on the post, when the channel signs posts. |
edited | boolean | Whether the post carries Telegram's "edited" mark. |
scrapedAt | string | When this run read the page, ISO 8601 in UTC. |
The channel record carries channel, title, description, url, imageUrl, subscribers,
subscribersText, photosCount, videosCount, filesCount, linksCount and scrapedAt. A count is
null when the channel's preview does not show it.
Media type is one of photo, video, roundvideo, voice, document or sticker. Photos, videos
and voice notes come back with a direct CDN URL. Documents do not: Telegram's preview publishes the file
name and size but no download link, so url is null for them.
How much does it cost to scrape Telegram channels?
This Actor uses pay per event pricing with platform usage included, so these two numbers are the whole bill:
| Event | Price | When it is charged |
|---|---|---|
| Actor start | $0.005 | Once per run (at the default 1 GB of memory) |
| Result | $0.002 | Per message saved, and per channel record (one for each channel) |
That is $2 per 1,000 posts. Some example runs:
| Run | Results | Cost |
|---|---|---|
| Default input: 40 posts from 2 channels | 82 | $0.17 |
| 100 posts from 1 channel | 101 | $0.21 |
| 1,000 posts from 1 channel | 1,001 | $2.01 |
| Keyword run over 500 posts that finds 4 matches | 5 | $0.02 |
| 10 channels × 50 posts | 510 | $1.03 |
| Only-new scheduled run, 3 new posts in 1 of 10 channels | 4 | $0.01 |
Messages that fail the keyword or date filter are read but never saved, so they cost nothing. With
onlyNewPosts on, posts an earlier run already covered are not saved again either, and a channel with
nothing new adds no channel record, so a scheduled run that finds nothing costs only the start event. The Apify
free plan includes $5 of monthly credit, enough for about 2,500 posts to try the Actor. To cap a single
run, set a maximum cost in the run options or lower maxItems.
Telegram scraper vs. the Telegram API
| This Actor | Telegram API (Telethon, Pyrogram) | Telegram Bot API | |
|---|---|---|---|
| What you need | Nothing | Phone number, api_id, api_hash, a session | A bot token, and the bot added as channel admin |
| Which channels | Any public channel with a web preview | Any channel your account can open | Only channels the bot administers |
| History | Pages back through the whole channel | Yes | No, only posts sent after the bot joins |
| Account risk | None, no account involved | Rate limits and bans hit your account | Tied to the bot |
| Forward counts, comments | No (the preview does not show them) | Yes | No |
| Scheduling, API, exports | Built in through Apify | You host and run it | You host and run it |
If you need forward counts, comments or private groups, you need an account-based client. For public channel posts, views and reactions, this Actor gets you there without one.
Use it through the API, integrations and AI agents
REST API. Run the Actor and get the results in one call:
curl -X POST "https://api.apify.com/v2/acts/thatmike1~telegram-channel-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"channels": ["durov"], "maxItems": 50}'
Node.js with apify-client:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('thatmike1/telegram-channel-scraper').call({channels: ['durov', 'telegram'],keywords: ['wallet'],maxItems: 50,});const { items } = await client.dataset(run.defaultDatasetId).listItems();const messages = items.filter((item) => item.type === 'message');
Python with apify-client:
from apify_client import ApifyClientclient = ApifyClient("YOUR_APIFY_TOKEN")run = client.actor("thatmike1/telegram-channel-scraper").call(run_input={"channels": ["durov"], "since": "2026-09-01", "maxItems": 0})for item in client.dataset(run["defaultDatasetId"]).iterate_items():if item["type"] == "message":print(item["date"], item["views"], item["text"][:80])
Integrations. Send results to Google Sheets, Slack, Zapier, Make, n8n, Airtable or any webhook with Apify integrations, and run it on a schedule for a hands-off feed.
AI agents (MCP). Give Claude, ChatGPT, Cursor or any MCP client a Telegram tool through the Apify MCP server:
$claude mcp add --transport http apify "https://mcp.apify.com?tools=thatmike1/telegram-channel-scraper"
Then ask in plain language, for example: "Get the last 100 posts from @durov and tell me which ones had the most views."
Tips for monitoring and large runs
maxItemsis per channel, not per run. Ten channels atmaxItems: 50is up to 500 messages. A shared budget would let the first channel eat all of it.maxScannedMessagesonly matters with keywords. A keyword run stops reading a channel after 500 messages by default, matching or not, so a rare keyword does not walk the whole history. Raise it, or set0, to search deeper. A run without keywords ignores it:maxItems: 1000returns 1,000 posts.- Scheduled monitoring without repeats. Turn on
onlyNewPostsand each run saves only posts newer than the newest one the previous run read, so nothing is charged twice. SetmaxItemsabove what a channel posts between two runs; anything beyond it in one run is skipped, not carried over. - Track reach over time. A post scraped twice keeps its
postIdand comes back with a higher view count, so repeated runs give you a views curve per post. - Proxies are optional. Telegram does not challenge these pages. Turn on Apify Proxy datacenter groups only if you run very frequently.
FAQ
Does this Actor need a Telegram account, phone number or API key?
No. It reads the public web preview at t.me/s/<channel>, which needs no login, no phone number, no
api_id and no bot token.
Which channels can it read? Any public channel that has a web preview, which covers most news, crypto and broadcast channels. Private and invite-only channels, groups, user accounts and bots have no preview: t.me redirects those to a plain landing page, and the Actor logs a warning, names them in the run's status message and skips them rather than failing the run.
Can it scrape Telegram groups or members? No. It reads channels only. Group chats and member lists are not on the public preview.
Does it return forward counts?
No, and no scraper of this page can. Telegram's public preview publishes views and reactions but not the
number of times a post was forwarded. What the Actor does return is forwardedFrom, the channel a post
was forwarded from.
Does it return comments?
No. replyTo is the in-channel reply chain. Comments live in the linked discussion group, which the
channel preview does not render.
Can it search all of Telegram by keyword? No. The keyword filter works inside the channels you list. You choose the channels; the Actor finds the posts in them that mention your terms.
Why is text sometimes empty?
A post can be media only, a poll only, or a forward with no caption. The text is an empty string rather
than null in those cases, and the content is in media or poll.
Why did I get fewer messages than I asked for?
Without keywords, only maxItems and since limit a run, so the channel is shorter than your limit or
your date cuts it off. With keywords, the Actor reads at most maxScannedMessages (500 by default) per
channel looking for matches; raise it or set 0 to search deeper. With onlyNewPosts on, posts an
earlier run already returned are left out on purpose.
How do I get only new posts on a schedule?
Turn on onlyNewPosts (Only new posts since the last run) and attach a schedule. When a channel
finishes, the Actor stores the newest post id it read in a key-value store named
telegram-channel-scraper-last-seen in your Apify account, one record per channel. The next run stops
paging when it reaches that post, so it saves and charges only what was published since. Things to know:
- The first run with it on has nothing stored yet and behaves like a normal run:
maxItemsandsincedecide how much it returns. - Each keyword filter is tracked separately (the record key is the channel plus a hash of the keywords),
because a keyword run marks every post it read as seen, matching or not. Two schedules on one channel
with different keywords do not steal each other's posts, and changing your keywords starts fresh.
since,maxItemsandmaxScannedMessagesare not part of the key. maxItemsstill caps each run. If a channel posted more than that since the last run, the newest are saved and the rest are skipped for good, so set it comfortably above a channel's posting rate.- A channel whose pages failed to load keeps its old position, so the next run retries it. That can repeat a few posts, but never loses any.
- To start over, delete the channel's record, or the whole store, under Storage → Key-value stores.
- A post's view count is not updated by later only-new runs. Turn the option off for a views curve.
Is scraping Telegram legal? This Actor reads only publicly available pages, the same ones anyone can open without an account, and does not bypass any access control. Scraping publicly accessible information is generally legal in the EU and the US, but you are responsible for how you use the output, including Telegram's Terms of Service, the privacy of the people posting and data protection law such as the GDPR. Talk to a lawyer if you plan to redistribute the data commercially.
Found a bug, or need something else? Open an issue on the Issues tab and it will be picked up. If you need a custom version or a field that is not covered here, say so in the issue.
More scrapers from the same developer
Website Tech Stack Detector for the sites a channel links to, Kalshi Prediction Markets Scraper for event odds next to the news, and Sports Odds Scraper for bookmaker prices.