Telegram Channel Scraper — Messages, Views & Media | from $3/1K
Pricing
from $2.91 / 1,000 message-scrapeds
Telegram Channel Scraper — Messages, Views & Media | from $3/1K
Scrape public Telegram channel messages with text, view counts, timestamps, media type, links, forwards, and reply threading — no API key, no login, no proxy required. Structural HTML parser (not class-name fragile) with parse_confidence drift signal. Paginates backwards via cursor.
Pricing
from $2.91 / 1,000 message-scrapeds
Rating
0.0
(0)
Developer
Vitalii Bondarev
Maintained by CommunityActor stats
0
Bookmarked
17
Total users
4
Monthly active users
2 days ago
Last modified
Categories
Share
Telegram Channel Scraper — Messages, Views & Media
Scrape messages from any public Telegram channel — no API key, no Telegram account, no proxy required. This Telegram channel scraper extracts message text, view counts, timestamps, media type, links, forward source, and reply threading from public channels accessible via t.me.
Use it for brand monitoring, crypto/news signal aggregation, competitive intelligence, or feeding Telegram content into LLM pipelines.
How the Telegram scraper works
Uses the public Telegram web preview at https://t.me/s/{channel} — the same URL anyone can open in a browser. Paginates backwards via ?before={message_id} to collect historical messages going as far back as the channel's public web history allows.
No unofficial MTProto API, no bot token, no phone number verification. Just HTTP + structural HTML parsing.
Why this Telegram scraper is more reliable than alternatives
Most Telegram scrapers use the MTProto API (requires a phone number and Telegram account) or depend on CSS class names that break on every Telegram web redesign. This actor uses structural XPath parsing on the semantic HTML structure — data-* attributes and element structure, not fragile class names. When Telegram updates its web UI, parse_confidence drops below 0.8 and warnings flag the affected fields — you get a drift signal, not silent wrong data.
Input
{"channels": ["telegram", "@durov", "https://t.me/cointelegraph"],"maxMessages": 200}
| Field | Type | Description |
|---|---|---|
channels | string[] | Public channel usernames, @handles, or t.me URLs |
maxMessages | integer | Max messages per channel (default: 100) |
beforeId | integer | Optional cursor — only collect messages before this ID |
Output
One row per message:
| Field | Type | Description |
|---|---|---|
channel | string | Channel username |
message_id | integer | Telegram message ID |
text | string|null | Message text content |
views | string|null | View count (e.g. "1.5M", "42K") |
datetime | string | ISO-8601 UTC timestamp |
has_media | boolean | Whether the message contains media |
media_type | string|null | "photo", "video", "document", "sticker", "audio", "poll" |
links | string[] | HTTP/HTTPS links in message text |
is_forwarded | boolean | Whether forwarded from another channel |
forward_from | string|null | Source channel/user name if forwarded |
reply_to | integer|null | Message ID being replied to |
message_url | string | Full https://t.me/{channel}/{id} URL |
parse_confidence | float | 0.0–1.0 quality signal; below 0.8 check warnings |
warnings | string[] | Parse quality warnings (e.g. "missing_datetime") |
scraped_at | string | ISO-8601 UTC scrape timestamp |
What it does NOT support
- Private channels — only public channels accessible via t.me/s/{channel}
- Comments/replies within posts — web preview shows channel messages only
- Media downloads — returns media type detection only, not URLs to media files
- Real-time streaming — pulls historical messages, not a live feed
Competitive edge
| Feature | This actor | @maximedupre/telegram-channel-messages-scraper |
|---|---|---|
parse_confidence field | ✓ | ✗ |
Pagination cursor input (beforeId) | ✓ | ✗ |
| Forward source name | ✓ | ✗ |
| Reply-to message ID | ✓ | ✗ |
| Structural parser (not class-name fragile) | ✓ | ✗ |
| Price | PPE $3/1K messages | ~$50/mo fixed |
Frequently asked questions
Can I scrape a private Telegram channel?
No. This actor only works on public channels accessible via t.me/s/{channel}. Private channels, groups, and direct messages are not supported.
Does this require a Telegram bot token or phone number?
No. The actor scrapes the public Telegram web preview (t.me/s/*) — no account, no bot token, no API credentials needed.
How far back can I scrape?
As far back as Telegram's public web preview stores. Most active channels have several years of history available. Use maxMessages and beforeId cursor to control the range.
Does it download media files?
No. The actor detects media type (photo, video, document, sticker, audio, poll) and returns the type flag, but does not download or return media URLs. This keeps the output lean and the cost low.
How is pricing calculated?
Pay-per-result (PPE) at $3.00 per 1,000 messages ($0.003/message). One charge (message-scraped event) per message pushed to the dataset. Failed fetches, retries, and pagination probes are not charged.
Integrations
Built for brand monitors, crypto-signal aggregators, and LLM-pipeline builders ingesting public Telegram channel content — the JSON/dataset output drops into the tools you already run, no glue code:
- n8n / Make / Zapier — trigger a run or pipe every new dataset item into 500+ apps (Google Sheets, Airtable, Slack, HubSpot, your database) with no code: n8n, Make, Zapier.
- Webhooks — fire your own endpoint the moment a run finishes, to push results straight into your pipeline (docs).
- MCP server — expose this actor as a tool to Claude, Cursor, or any MCP client so an AI agent can pull this data mid-conversation (guide).
- API & SDKs — fetch the dataset as JSON, CSV, or Excel through the Apify REST API or the Python / JS SDKs.
See all Apify integrations.
Legal
This actor scrapes the publicly accessible web preview of Telegram channels (t.me/s/*). This is identical to what a browser sees when visiting the URL. Only public channels (already freely accessible to anyone on the internet) are scraped.
Not affiliated with Telegram.
More scrapers from our toolkit
Building a data pipeline? These actors pair well with this one — each runs on your own Apify account with the same pay-per-result pricing, no subscription:
- Truth Social Scraper
- Twitch Scraper
- Douyin Scraper
- Maigret Username Osint
- Patreon Scraper
- Pinterest Scraper
Chain any of them together from the Integrations tab (the Run succeeded trigger) to build a multi-step workflow — one actor's output feeds the next.
Usage statistics
This Actor creates a small, content-free summary at the end of each run. It is used only to monitor reliability and improve this Actor. A copy is saved as USAGE_STATS in your own Apify key-value store, so you can see the exact record created for your run.
Set disableUsageStats to true in the input to opt out. Nothing is sent then; your USAGE_STATS record only says that statistics were disabled.
Only these fields are recorded:
- schema version, Actor name and build number;
- UTC start and finish hour (not a precise timestamp);
- run duration, number of results and time to the first result, each as a coarse range;
- whether the result was empty, the end status, and an error type from a fixed list;
- memory setting and counts of charged events;
- names of the input fields you set, never their values;
- the selected option for input fields that offer a fixed list of choices (for example a sort order).
We do not collect input text, search terms, URLs, domains, usernames, email addresses, names, proxy credentials, tokens, scraped records, output items, raw error messages, stack traces, or hashes of any of those values. Records are kept for no longer than 13 months, used only as aggregated operational statistics, and never sold or shared.
Additional fields (Phase 2)
This Actor also records your Apify user ID, whether Apify marks the account as paying, the size range of list inputs, the selected country when the input offers a fixed list of countries, and one category from a fixed Actor taxonomy. We use these fields only for aggregate reliability, repeat-use and cross-Actor analysis; reports suppress any cell with fewer than five distinct users.
The same disableUsageStats: true input flag turns these fields off too. The user ID is removed after 13 months; we do not export, sell, share, or attempt to re-identify this data.
Run-outcome signals (v2)
To learn whether a run did what it was asked to do, the record also holds a few more coarse ranges and yes/no flags. None of them contains content:
- the result limit you asked for (a range, when the input has one) and what share of it was delivered;
- results delivered per input item you listed (a range);
- output quality as ranges: how fully the result fields were filled, the share of rows that look like errors, the share of duplicate rows, and how many different fields appeared. These are counted in memory while results are saved; no result content is kept;
- how the run was started (console, API, schedule, webhook, another Actor);
- how it ended: stopped by you, timed out, reached the requested limit, stopped by the charge limit, and how many times the platform moved the run;
- if this Actor reports it: how many items to process worked or failed (ranges) and one failure reason from a fixed list;
- a short code made from the names of the input fields you set, never their values.
Repeat-run fingerprint (v2)
When your Apify user ID is recorded (see above), the record also holds an 8-character one-way code made from your input (proxy settings left out) and this Actor's name. It only lets us see that the same account ran the same input again soon after an unsatisfying run; we never see the input itself. It is stored only in the database, never published, and reports use it in aggregate with the same five-user minimum. It is the one exception to the statement above that no hashes are collected, and disableUsageStats: true turns it off.