Telegram Channel Scraper: Messages, Views & Channel Info avatar

Telegram Channel Scraper: Messages, Views & Channel Info

Pricing

Pay per event

Go to Apify Store
Telegram Channel Scraper: Messages, Views & Channel Info

Telegram Channel Scraper: Messages, Views & Channel Info

Export public Telegram channel messages — text, view counts, media type, links, hashtags, reply and edit info — plus channel title, description and subscriber count. No Telegram login, no phone number, no API ID: reads the public t.me/s preview.

Pricing

Pay per event

Rating

0.0

(0)

Developer

Changefeeds Tools

Changefeeds Tools

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

Give it a list of public Telegram channels and it exports their messages — text, views, hashtags, links, media type, reply and edit info — plus one row per channel with title, description, subscriber count and photo. Built for "telegram scraper" / "telegram channel messages export" jobs: research digests, competitor monitoring, dataset building, archiving a public channel's posts. No Telegram login, no API ID, no phone number — it reads the same public t.me/s/<channel> preview a logged-out browser sees.

This is a plain, one-shot export. If you need a run-over-run change feed (only what's new, edited, deleted or view-changed since the last check), see our companion actor Telegram Channel Monitor – Change Feed.

Input

FieldDefaultNotes
channelsrequiredChannel usernames: durov, @durov, t.me/durov, https://t.me/s/durov all work. Up to 1,000 per run. Invalid entries become an error row; the run continues.
maxMessagesPerChannel2001 to 10,000. Pages backwards through the preview using its ?before=<id> cursor.
sincenoneISO date/time. Only messages on or after it are exported; pagination stops once it reaches older ones.
untilnoneISO date/time. Only messages on or before it are exported.
keywordsnoneKeep only messages whose text contains at least one keyword (case-insensitive). Leave empty to keep everything.
includeChannelInfotrueAlso emit one row per channel with title, description, subscribers, photo, verified badge.
{
"channels": ["durov", "telegram"],
"maxMessagesPerChannel": 20,
"includeChannelInfo": true
}

Output

One message row per exported message:

{
"type": "message",
"channel": "durov",
"message_id": 549,
"url": "https://t.me/durov/549",
"date": "2026-09-05T10:00:00+00:00",
"text": "Something new happened today.",
"views": 812000,
"forwarded_from": null,
"reply_to_id": null,
"has_media": false,
"media_type": null,
"media_urls": [],
"links": ["https://telegram.org"],
"hashtags": [],
"edited": false,
"author": null
}

One channel row per channel, when includeChannelInfo is on:

{
"type": "channel",
"channel": "durov",
"title": "Pavel Durov",
"username": "durov",
"description": "Founder of Telegram.",
"subscribers": 10600000,
"verified": true,
"photo": "https://cdn4.telesco.pe/file/....jpg",
"messages_returned": 20,
"checked_at": "2026-09-29T12:00:00.000Z"
}

Channels that fail get a free channel status row instead of message rows — the run never charges for a channel it couldn't read:

{
"type": "channel",
"input": "thischanneldoesnotexist9x7q",
"channel": "thischanneldoesnotexist9x7q",
"status": "not_found",
"error": null,
"checked_at": "2026-09-29T12:00:00.000Z"
}

status is one of:

  • not_found — the username does not resolve to a channel.
  • private_or_no_preview — the page shows Telegram's contact card but with channel content on it (see Limits below) — likely a channel that exists but whose message preview isn't public.
  • error — the page failed to load after retries.
  • invalid — the input entry is not a valid channel username.

The key-value store record OUTPUT holds a per-channel and per-run summary (counts, HTTP stats, stopped_reason, charged_events). Every run leaves at least one dataset row, even a run that matches nothing, so a quiet run is never mistaken for a broken one.

Pricing

Pay per event, nothing else:

  • $0.002 per channel checked (only charged when includeChannelInfo is on and the channel loaded successfully).
  • $0.001 per message returned ($1 per 1,000 messages).

Example: 3 channels, 200 messages each, with channel info = 3 × $0.002 + 600 × $0.001 = $0.61. If you set a maximum total charge for the run, the actor stops cleanly once it's reached, delivering only what it already charged for, and says so in OUTPUT.stopped_reason ("max_total_charge_reached").

Limits, stated plainly

  • Public channels only. The actor reads https://t.me/s/<channel> — exactly what a browser without a Telegram account sees. Private groups, member lists and phone numbers are never available this way.
  • not_found vs private_or_no_preview is a best-effort guess. Telegram's logged-out contact-card page looks nearly identical whether a username is simply unregistered or belongs to a channel whose preview isn't public; the actor infers which from whether the page carries any channel content. Don't treat the distinction as authoritative.
  • No media download. Photos, videos and documents only set media_type and, when the page's HTML happens to expose one (a photo/video thumbnail URL, a document link), media_urls. No files are fetched.
  • reply_to_id and author are best effort. They come from the reply preview block and the "Sign messages" signature the page shows, when present; many channels show neither.
  • View counts are approximate by nature. Telegram rounds the public counter (2.67M, 1.2K); a re-run may show a slightly different number.
  • It stays polite: at most 2 channels fetched at a time, at least 1.5 s between page requests of the same channel, HTTP 429 honoured (Retry-After, capped at 60 s, max 3 retries), a normal browser-like User-Agent, 20 s timeouts. A channel needs roughly 1 page per 20 messages, so exporting 10 channels × 200 messages takes a couple of minutes.

FAQ

Can this scrape private channels or groups? No. Only channels with a public username and a public web preview.

Does it get member lists or phone numbers? No, never — the public preview never exposes those.

Can I get only messages from the last week? Yes, set since to an ISO date; pagination stops once it reaches older messages, so this is also cheaper than exporting everything and filtering afterward.

Can I filter by topic? Yes, use keywords — case-insensitive substring match against the message text.

I need a daily digest of only what changed, not a full re-export. Use our companion actor, Telegram Channel Monitor – Change Feed, instead.

Local development

pnpm --filter @mmnm/tgexport test # unit tests, no network
pnpm --filter @mmnm/tgexport build

node src/main.ts runs the actor locally with Apify's local storage (./storage); ACTOR_TEST_PAY_PER_EVENT=true ACTOR_MAX_TOTAL_CHARGE_USD=1 exercises the charging path with the SDK's $1 local test price.