Telegram Channel Scraper - Posts, Views, Media avatar

Telegram Channel Scraper - Posts, Views, Media

Pricing

from $1.00 / 1,000 run start fees

Go to Apify Store
Telegram Channel Scraper - Posts, Views, Media

Telegram Channel Scraper - Posts, Views, Media

Scrape posts from any public Telegram channel: full text, publish time, view counts, media flags, forwards and outbound links, plus channel title and subscriber count. No login, no bot token.

Pricing

from $1.00 / 1,000 run start fees

Rating

0.0

(0)

Developer

SR

SR

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

1

Monthly active users

7 days ago

Last modified

Share

Read the posts of any public Telegram channel: the full text, when it was published, how many people saw it, whether it carries a photo or a video, what it forwards, and every external link in it. Every row also carries the channel's display name and subscriber count, so a post's reach can be read against the size of its audience.

No login, no bot token, no API registration. Give it channel names, get back one row per post.

What you get

  • One row per post, newest first within each channel, with a stable post identifier (durov/546) you can join runs on.
  • Text with its shape intact. Line breaks and emoji survive, so a fifteen-paragraph post does not arrive as one line.
  • View counts twice: views_text exactly as Telegram shows it (2.76M) and views as an integer (2760000) that sorts and sums correctly.
  • Attribution: the channel owner name, per-post signatures where a channel uses them, and forwarded_from when a post came from elsewhere.
  • Media and link flags: has_photo, has_video, has_link_preview, is_reply, and outbound_links with Telegram's own domains removed.
  • Channel context on every row: channel_title and subscribers at the time of the run.

What a row looks like

A row from a run of the default input on the current build, unchanged:

{
"channel": "durov",
"message_id": 546,
"post": "durov/546",
"url": "https://t.me/durov/546",
"text": "🏳️ Gram Wallet in Telegram is ready and is now accessible to a select group of users.\n\n🤩 We'll be gradually rolling it out to our billion+ users over the next couple of weeks.\n\n⚡️ Thanks to the validators who approved the smart contract that powers it, future upgrades of the wallet won't require painful migrations.\n\nThis is just one of the innovations we've built to make non-custodial wallets usable ✨",
"text_length": 404,
"posted_at": "2026-08-31 16:30:15",
"views_text": "2.76M",
"views": 2760000,
"author": "Pavel Durov",
"signature": null,
"forwarded_from": null,
"is_forwarded": false,
"has_photo": false,
"has_video": true,
"has_link_preview": false,
"is_reply": false,
"outbound_links": null,
"channel_title": "Pavel Durov",
"subscribers": 10700000,
"position": 3
}

That run read two channels and returned 100 posts in 26 seconds: 99 with text, 100 with a view count, 57 with a photo or video.

Input

FieldTypeDefaultExampleWhat it controls
channelsarray of strings["durov", "telegram"]["durov", "t.me/telegram", "@bloomberg"]The public channels to read. A t.me/name link or an @name is reduced to the bare name. Names must be 4 to 32 characters of letters, digits and underscores; anything else is reported as bad_input and skipped.
limitinteger, 1 to 5000100500The total number of posts across all channels, divided evenly, so 100 over two channels is 50 each. A higher limit means more pages and a longer run; the Actor waits one to two seconds between pages.
retriesinteger, 1 to 846How often a page is retried with backoff before it is reported as fetch_failed. Raise it for a long unattended run; lower it if a fast answer matters more than a complete one.

Paging walks backwards through message ids: each request asks for the posts older than the lowest id seen so far. There is no page count and no total, so a channel is finished when a page returns nothing new, when its share of limit is reached, or after 40 pages.

Output

One row per post in the default dataset.

FieldMeaning
channelChannel username
message_idMessage number within the channel
postchannel/message_id. Stable, join runs on it
urlDirect link to the post
textPost text with line breaks preserved, capped at 8,000 characters
text_lengthCharacters of text
posted_atWhen it was published, UTC
views_textView count as Telegram shows it, for example 1.2K
viewsView count as an integer, which is what sorts correctly
authorChannel owner name shown on the post
signaturePer-post author signature, when the channel uses them
forwarded_fromOriginal channel, when the post is a forward
is_forwardedWhether the post is forwarded from elsewhere
has_photoWhether the post carries a photo
has_videoWhether the post carries a video
has_link_previewWhether a link preview card is attached
is_replyWhether the post replies to another
outbound_linksExternal links in the post, Telegram's own excluded, at most 20
channel_titleDisplay name of the channel
subscribersSubscriber count at the time of the run
positionRow position in this run

The key-value store holds two more records. summary carries postsReturned, channelsRead, withText, withViews, withMedia, forwarded, fetchedInSeconds and errorCount. errors lists each failure with a code and a message, and is only written when something went wrong.

Pricing

Pay per event, no subscription.

  • $0.001 per post returned (post).
  • $0.001 per run start fee (run_start).

A run that returns 100 posts costs $0.101. A run that returns 1,000 posts costs $1.001. Posts are billed only when they land in the dataset, so a channel that turns out to be private costs nothing beyond the start fee.

Free Apify plans receive at most 10 rows per run and are billed for those 10, not for the posts fetched and discarded. A paid Apify plan removes the cap.

Limits and failure modes

  • Public channels only. A private channel, a group or a user account has no public preview. Telegram answers with a valid page that contains no posts, which is easy to mistake for a channel that never posted. The Actor recognises that page and reports not_a_public_channel naming the channel, while every other channel in the run continues.
  • A run with no rows still succeeds. The dataset is empty, summary.errorCount is set, and errors holds the reason: bad_input for names that fail validation, not_a_public_channel, fetch_failed when a page failed after all retries, or no_results when a channel exists and has nothing to show.
  • Per-channel ceiling. The walk stops after 40 pages per channel. For a deep archive, run the channel on its own with a high limit rather than sharing the limit across many channels.
  • Timeouts. Each page request is given 40 seconds. The default run timeout is 300 seconds; a limit of several thousand across many channels can need more, so raise the run timeout in the run options for large jobs.
  • views can be null. Some channels hide view counts. That is the channel's setting, and it comes back as null rather than zero.
  • Rounded subscriber counts. Telegram rounds them: a channel of 10.7M is reported as 10,700,000, not to the person.
  • No comments, reactions or media files. These live in the app rather than the web preview. has_photo and has_video tell you a post carries media; the files are not downloaded.
  • No historical view counts. views is the count at the moment of the run. Schedule the Actor and join on post to watch a number grow.

Use cases

Competitor and market monitoring. "I want to know what the channels in my sector publish and which posts actually travel." Read them weekly, divide views by subscribers for an engagement rate, and rank posts across channels on one scale.

News and signal collection. "Announcements in my niche land on Telegram before anywhere else." Schedule the Actor, join each run on post, and pipe only the new rows into a feed or an alert.

Content research. "Which topics does this audience respond to?" text next to views shows which subjects a channel's readers open. Filter on has_video to compare formats.

Link and campaign tracking. "Where does this channel send its readers, and who amplifies it?" outbound_links shows the destinations; is_forwarded with forwarded_from maps how a message moves between channels.

Run it from the API

Start a run with the default input and read the dataset when it finishes:

curl -X POST "https://api.apify.com/v2/acts/s-r~telegram-channel-scraper/runs?token=YOUR_APIFY_TOKEN&waitForFinish=120" \
-H "Content-Type: application/json" \
-d '{"channels": ["durov", "telegram"], "limit": 100, "retries": 4}'

The response carries data.defaultDatasetId. Fetch the rows with:

$curl "https://api.apify.com/v2/datasets/DATASET_ID/items?token=YOUR_APIFY_TOKEN&format=json"

Use format=csv or format=xlsx for a spreadsheet.