Telegram Channels Scraper: Messages, Contacts & Leads
Pricing
from $2.00 / 1,000 messages
Telegram Channels Scraper: Messages, Contacts & Leads
Scrape public Telegram channel messages with every email and link in each post pulled out for you, plus views, reactions and media. Schedule it to collect only new messages, with no account or phone number.
Pricing
from $2.00 / 1,000 messages
Rating
0.0
(0)
Developer
Khadin Akbar
Maintained by CommunityActor stats
2
Bookmarked
424
Total users
75
Monthly active users
46 days
Issues response
6 days ago
Last modified
Categories
Share
What is Telegram Channel Scraper?
Telegram Channel Scraper turns public Telegram channel names or t.me links into a clean dataset of messages. Each message row has the text, post date, view count, reactions, media type and link, forward source, and any links and email addresses found in the text. An optional channel row adds the title, description, subscriber count and verification. Researchers, marketers, lead-gen teams, analysts and AI agents use it to monitor channels and pull contacts, with no Telegram account, phone number or login.
Why teams choose this Telegram scraper
- Contacts pulled out for you.
extracted_emailsandextracted_linkslist every email address and URL found in each message, ready for lead lists. - Channel overview in the same dataset. With
includeChannelInfo, onechannel_inforow adds subscribers, description and verification. - Only new messages on a schedule.
sinceLastRunremembers the last message seen per channel, so scheduled runs return only fresh posts. - Date-bounded history.
oldestMessageDatestops paging at the date you choose, so a backfill is exactly as deep as you need. - Channel discovery.
discoverRelatedlists channels that your channels forward from, a quick way to map a niche. - Built for AI agents. Every message also carries a compact
markdown_previewfor LLM context, with flat JSON through Apify MCP and the API.
Best fit for this Actor
- Start here when you know the public channels you want and need their messages, links and contacts.
- For finding channels by keyword first, start with Telegram Keyword Search Scraper and pass the channel handles into
channels. - For channel statistics only, with no messages, use Telegram Channel Info Scraper instead.
- Channels work when their public web preview (
https://t.me/s/<channel>) is on, which is the case for most public channels.
What people and AI agents ask this Actor to do
Get the last 200 messages from these three crypto channels. Pull every email address posted in this channel. Monitor these news channels and give me only new posts each morning. Which channels does this channel forward from?
| Request | Input to send |
|---|---|
| Recent messages from a few channels | {"channels": ["durov", "telegram"], "maxMessagesPerChannel": 200} |
| Contacts posted in a channel | {"channels": ["durov"], "maxMessagesPerChannel": 1000}, then read extracted_emails |
| Daily monitoring of new posts | {"channels": ["durov"], "sinceLastRun": true} on a daily schedule |
| History back to a date | {"channels": ["durov"], "oldestMessageDate": "2026-01-01", "maxMessagesPerChannel": 5000} |
| Map related channels | {"channels": ["durov"], "discoverRelated": true} |
| Lean text rows for an LLM | {"channels": ["durov"], "includeMedia": false, "includeReactions": false} |
Example workflow: from a channel list to a lead sheet
A B2B marketer starts with ten public channels in their industry. They send the handles in channels with maxMessagesPerChannel set to 500. The dataset returns each message's message_text, posted_at, view_count, extracted_emails and extracted_links, plus one channel_info row per channel. They keep the messages that contain emails, export them to a spreadsheet, then schedule the same input with sinceLastRun on so each morning adds only new posts and new contacts.
How to scrape Telegram channels
- Add channel usernames,
@handlesort.melinks in Channels. - Set Max messages per channel, and optionally Oldest message date or Since last run.
- Click Start. Export the dataset as JSON, CSV or Excel, or read it through the API.
Quick start input
{"channels": ["durov", "telegram"],"maxMessagesPerChannel": 100,"includeChannelInfo": true,"includeMedia": true,"includeReactions": true,"sinceLastRun": false,"discoverRelated": false}
Input reference
| Field | Type | What it controls |
|---|---|---|
channels | array of strings | Public channel usernames, @handles or t.me links. |
maxMessagesPerChannel | integer | Cap on messages per channel. Default 100. |
includeChannelInfo | boolean | Add one channel_info row per channel. Default true. |
includeMedia | boolean | Include media type and media URL on each message. Default true. |
includeReactions | boolean | Include the reaction breakdown on each message. Default true. |
oldestMessageDate | string | Stop at messages older than this date, in YYYY-MM-DD format. |
sinceLastRun | boolean | Return only messages newer than the previous run. Default false. |
discoverRelated | boolean | Add discovered_channel rows for channels your channels forward from. Default false. |
outputFormat | string | Kept so older saved inputs keep working; every message already includes markdown_preview. |
proxyConfiguration | object | Optional Apify Proxy settings. |
Output: Telegram channel data you receive
Each dataset row has a record_type. Message rows are the main output.
record_type | What one row represents |
|---|---|
message | One public channel message |
channel_info | One channel overview (with includeChannelInfo) |
discovered_channel | One related channel handle (with discoverRelated) |
channel_error | A channel whose public preview is off, with a note on how to check it |
run_summary | Totals for the run: messages, emails, links and channels |
Message fields:
| Field | What it contains |
|---|---|
channel_username, message_id, message_url | Channel, message ID and direct link |
message_text, posted_at | Text and post time |
view_count, reaction_count, reactions | Views and reactions |
has_media, media_type, media_url | Media details |
is_forwarded, forwarded_from, in_reply_to | Forward and reply context |
extracted_links, extracted_emails | Links and email addresses found in the text |
markdown_preview | One-line markdown summary of the message for LLM prompts |
source_url, scraped_at | Provenance and collection time |
{"record_type": "message","channel_username": "durov","message_id": "531","message_text": "🩵 Telegram now has a Rich Text Editor.\n\nIt supports tables, headings, inline media, lists, AI content, formulas, and more.\n\n\n😈 Messaging apps will never be the same!","posted_at": "2026-07-16T20:45:25+00:00","view_count": 5730000,"reaction_count": 0,"is_forwarded": false,"forwarded_from": null,"has_media": true,"media_type": "video","media_url": "https://cdn4.telesco.pe/file/b231b9b161.mp4?token=UG9wsSyeVAOA7L87kUFppLT6N-AKz0c7PuG1BHRgLu5uISDSQP98p-9NnlN7-qiJQIDcaiGdER7teY91Yv9FzhkhIeH9PRwyOV8-TTRBxmhN_sNB4G_UOTBUDQRW5yg4nKww1utDGXuQ_6rZNZlk9b4w_hgT4rlvCw4riJUrYzyMq07Uo2OZYWbH7Tysj4UDJhrB-WR3iTwraWCbYa9_KVnj_fvtcrB-QR9VUPYO1frGbT8fpAJ3Bpys4Esg9FvRgNJhUi0L34ZHxkVKqDyn-mhcOLcQ_l-UMAeVZZCe39Y9h7SyKhzgXLeD19ZbYy51kk5ReSsmL2S2hRiN66qFJTzoLYYGMqknLXWitR9ENcuYlvuH2_duRcW1gSNrDutwJRiNb4oohoOr2QiJZhWoYyGpijaw_6z9cGAq5qraeb67jIHbQJRGf3qFSIx1nXYKlYBH2IGEFbmyeDQT784STQ5YPI-eEt4U2NpNTzs5qqOhyJVQlX8AwFaoOXyE8JMF1U5N6F2kgYRk9lSL-fG7i4rS94h3rQJ8XKuOf9GXGF6tJT-wZRWgCS1AQJnzDxJQ0sz9GR52DM9Ho7mOsVJxsH0JrprSkZ-jLGCuNWz4izHcr0djjMAgjRxHVogYUkwXcmv5R27x7EdgEMGthHOr_gJwSqXM3BRMKCcD7HrBjy0","extracted_links": [],"extracted_emails": [],"message_url": "https://t.me/durov/531","source_url": "https://t.me/s/durov","scraped_at": "2026-09-29T09:57:41.733Z"}
What each run outcome means
Every run writes an OUTPUT record and a RUN_SUMMARY record to the default key-value store. Read OUTPUT.outcome to branch in code or in an agent.
| Outcome | Meaning |
|---|---|
COMPLETE | Messages were collected from the requested channels. |
PARTIAL | Messages were saved and a time budget or charge cap ended the run early. |
VALID_EMPTY | The request was valid and there were no messages to return, for example no new posts since the last run. |
UPSTREAM_FAILED | Telegram's public preview was unavailable for every requested channel. |
Pricing
This Actor uses Pay per event. Apify platform usage is included in the event prices, so you pay only for events: one message event per saved message, one channel-info event per channel_info row, and one start event per run. discovered_channel, channel_error and run_summary rows are free. The live Pricing tab on this page shows the current event prices.
Worked examples:
- 3 channels × 100 messages with channel info = 300 message events + 3 channel-info events + 1 start event.
- A daily
sinceLastRunrun that finds 12 new posts = 12 message events + channel-info events + 1 start event. includeChannelInfo: false= message events + 1 start event only.
Formula: message price × saved messages + channel-info price × channels + start event. Set a maximum charge per run in the run options to cap spend.
Use Telegram Channel Scraper with AI agents (MCP)
Connect this Actor to Claude, ChatGPT, Cursor or any MCP client through Apify MCP, then ask in plain language:
Collect the latest 100 messages from the public Telegram channels durov and telegram. Return message text, post date, view count, links and emails, and tell me the outcome and how many emails were found.
Agent checklist:
- Pass channel handles in
channelsand setmaxMessagesPerChannelto the depth you need. - Read rows with
get-dataset-items; keep rows whererecord_typeismessage. - Read
OUTPUT.outcome, and therun_summaryrow for totals. - Feed
markdown_previewinto prompts when you want compact message text. - Keep
message_urlandscraped_atto cite each message.
API example
curl -X POST "https://api.apify.com/v2/acts/khadinakbar~telegram-channel-scraper/run-sync-get-dataset-items" \-H "Authorization: Bearer $APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"channels": ["durov"], "maxMessagesPerChannel": 50}'
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('khadinakbar/telegram-channel-scraper').call({channels: ['durov', 'telegram'],maxMessagesPerChannel: 50,});const { items } = await client.dataset(run.defaultDatasetId).listItems();const emails = items.filter((row) => row.record_type === 'message').flatMap((row) => row.extracted_emails ?? []);console.log(emails);
Choosing the right Telegram tool
Other Actors from the same developer pick up where this one stops.
| Your starting point | Tool to use | Why it fits |
|---|---|---|
| When you know the channels and want their messages | This Actor | Messages, links, emails and channel info |
| When you start from a keyword or topic | Telegram Keyword Search Scraper | Matching channels, groups and messages; pass the handles into channels here |
| When you want channel stats only | Telegram Channel Info Scraper | Subscribers, bio, verification and engagement to compare many channels first |
| When you want the people active in a group or channel | Telegram Members Scraper | Active members from the public preview |
| When you want the photos and videos themselves | Telegram Media Downloader | Permanent copies of the files behind media_url |
Best results
| Starting situation | Helpful action | Expected outcome |
|---|---|---|
| Known public channels | Use exact usernames or t.me links | Clean message rows |
| Ongoing monitoring | Schedule with sinceLastRun on | Only new posts each run |
| A dated backfill | Set oldestMessageDate and a high maxMessagesPerChannel | History back to that date |
| Messages for an LLM | Set includeMedia and includeReactions to false and use markdown_preview | Compact text rows |
A channel_error row appears | Open https://t.me/s/<channel> to confirm its public preview | A clear answer on whether the channel is readable |
Builder's note
I found that most Telegram research ends in two questions, what was said and who to contact, so every message row carries extracted_emails and extracted_links alongside the text. I learned that monitoring beats one-off pulls for Telegram, which is why sinceLastRun keeps the last message ID per channel and scheduled runs return only fresh posts.
FAQ
Do I need a Telegram account or phone number?
No. The Actor reads Telegram's public web preview and needs no account, phone number or API key.
Can I scrape private channels or groups?
The Actor reads public channels whose web preview is on. Private channels and groups you would need to join are outside its public-data scope.
How much does it cost to scrape 1,000 Telegram messages?
1,000 messages cost 1,000 message events plus channel-info events for each channel and one start event. Platform usage is included. Multiply by the prices on the Pricing tab.
How do I get only new messages every day?
Set sinceLastRun to true and schedule the Actor. Each run returns messages newer than the last one it saw.
What if a channel returns no messages?
Its public web preview is probably off, and the Actor writes a free channel_error row for it. Open https://t.me/s/<channel> in a browser; if no messages show there, the channel is readable only inside the Telegram app.
Responsible use
This Actor collects public Telegram channel content only. Messages can contain names, usernames and email addresses, which are personal data protected by laws such as the GDPR and CCPA. Collect and use them only with a lawful basis, honor opt-outs before any outreach, keep data no longer than you need, and respect Telegram's terms. Read Apify's guide on whether web scraping is legal for more context. Telegram is a trademark of its owner. This independent Actor is not affiliated with, associated with, or endorsed by Telegram. For questions or bugs, open a ticket in the Issues tab.