Telegram Channel Scraper π¨ Messages, No Bot Token
Pricing
from $1.43 / 1,000 message returneds
Telegram Channel Scraper π¨ Messages, No Bot Token
Scrape messages from any public Telegram channel. Pass channel names or t.me links; get message text, view count, date, message ID, photo and video flags and a direct link as JSON or CSV. No API key, bot token or phone number. Since date filter keeps runs cheap.
Pricing
from $1.43 / 1,000 message returneds
Rating
0.0
(0)
Developer
Yaniv van der Stigchel
Maintained by CommunityActor stats
1
Bookmarked
2
Total users
1
Monthly active users
4 hours ago
Last modified
Categories
Share
Telegram Channel Scraper β no API key, no bot token
Export messages from any public Telegram channel. Text, view counts, timestamps, direct links and media flags. No bot token, no phone number, no login.
Scrape public Telegram channels
- Export Telegram channel messages to JSON or CSV
- Download a Telegram channel's post history
- Monitor a Telegram channel for new messages
- Get Telegram post view counts and engagement
- Archive a public Telegram channel
Pass several channels at once. Every row is tagged with its source channel.
Incremental mode β cheap scheduled runs
Set since to the date of your last run and the scraper stops as soon as it
reaches older messages. A daily monitoring job costs a fraction of a full
back-scrape, because it only returns what is new.
What you get per message
Message text (HTML stripped, entities decoded), view count as a number, ISO
timestamp, message id, direct t.me link, and flags for photo, video and
forwarded content.
Honest failure reporting
Private channels, deleted channels and misspelled names return a row with
reason: "channel-unavailable" β and cost you nothing. You are only charged
for messages actually delivered.
Input
| Field | Required | Description |
|---|---|---|
channels | yes | Names, @handles, or t.me URLs |
maxMessagesPerChannel | no | Newest first. Default 200. Your cost ceiling. |
since | no | ISO date. Only messages after it. |
proxy | no | Optional β not needed for typical runs |
Example input
{"channels": ["@telegram", "durov"],"maxMessagesPerChannel": 500,"since": "2026-08-01"}
Output
Every row has the same fields whether it succeeded or failed, so you can select columns without branching. Failed rows are never charged.
| Field | Type | Description |
|---|---|---|
success | boolean | True when this row carries data. Failed rows are never charged. |
sourceChannel | string | The channel input this row came from. |
messageUrl | string | Public t.me link to the message. |
messageId | integer | Sequential message number within the channel. |
text | string | The message body as published. |
publishedAt | string | ISO 8601 timestamp of publication. |
viewCount | integer | Views at the time of the run. Null when Telegram does not expose it. |
hasPhoto | boolean | True when the message includes a photo. |
hasVideo | boolean | True when the message includes a video. |
isForwarded | boolean | True when the message was forwarded from elsewhere. |
errorCode | string | Machine-readable failure reason. Null on success. |
errorMessage | string | Human-readable explanation of the failure. Null on success. |
Example β success
{"success": true,"sourceChannel": "durov","messageUrl": "https://t.me/durov/526","messageId": 526,"text": "Telegram now supports gifting Premium subscriptions to any user.","publishedAt": "2026-08-14T09:12:04+00:00","viewCount": 1284000,"hasPhoto": true,"hasVideo": false,"isForwarded": false,"errorCode": null,"errorMessage": null}
Example β failure
A failure carries the same fields, so nothing downstream has to branch.
{"success": false,"sourceChannel": "private_example_channel","messageUrl": null,"messageId": null,"text": null,"publishedAt": null,"viewCount": null,"hasPhoto": null,"hasVideo": null,"isForwarded": null,"errorCode": "channel-unavailable","errorMessage": "No public Telegram channel exists at this name, or it is private."}
Error codes
channel-unavailableunparseable-channelno-messages-founderror
Use it for
- Telegram channel messages β full text history from public channels
- Telegram channel archive β a durable copy of a public channel
- Public Telegram channel monitoring β scheduled runs with a since filter
- Telegram backup β a durable local copy of a public channel's history
- OSINT, news tracking and market monitoring
- Research corpora and training datasets
Use it from an AI agent (MCP)
This Actor is callable as a tool through the Apify MCP server, so Claude, ChatGPT, Cursor and VS Code can run it directly.
Add the server to your MCP client:
{"mcpServers": {"apify": {"url": "https://mcp.apify.com","headers": {"Authorization": "Bearer <YOUR_APIFY_TOKEN>"}}}}
Then ask for what you want in plain language β for example βget the recent messages from this public Telegram channelβ β and the agent calls cleanfeed/telegram-channel-archive-scraper with the right input. Every output field is described in the dataset schema, so the agent knows what it is getting back before it runs anything.
Call it from code
Python
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("cleanfeed/telegram-channel-archive-scraper").call(run_input={"channels": ["durov"],})for item in client.dataset(run["defaultDatasetId"]).iterate_items():if item["success"]:print(item)
JavaScript
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('cleanfeed/telegram-channel-archive-scraper').call({channels: ["durov"],});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items.filter((i) => i.success));
cURL
curl -X POST "https://api.apify.com/v2/acts/cleanfeed~telegram-channel-archive-scraper/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \-H 'Content-Type: application/json' \-d '{"channels": ["durov"]}'
Related actors
| If you need | Use |
|---|---|
| Posts from public Bluesky accounts | Bluesky Posts Scraper |
| Posts from public Threads profiles | Threads Posts Scraper |
Limitations
- Public channels only. Private channels, groups and direct messages are not accessible and never will be by this route.
- No bot token or phone number is used, so there is no account to get restricted.
viewCountis null when Telegram does not publish it for a message.- Use the
sincefilter for scheduled runs so each run only collects and charges for what is new.
FAQ
Do I need a bot token or phone number?
Neither. Public channel pages are read directly, so there is no API key, no bot and no account to get restricted.
Can I read private channels or groups?
No. Only public channels are accessible.
What channel formats work?
A channel name such as durov, an @durov handle, or a t.me/... link.
How do I keep scheduled runs cheap?
Set since to an ISO date. Each run then collects and charges only for messages published after it.
Why is viewCount sometimes null?
Telegram does not publish a view count for every message. The field is null rather than guessed.
Notes
Only public channels and publicly visible content. No bot token, no user account, no private groups, no personal data beyond what the channel publishes.