Telegram Channel Posts Scraper
Pricing
from $1.48 / 1,000 results
Telegram Channel Posts Scraper
Collect public Telegram channel posts with date, text, views, photos, video, links and reactions, plus optional channel profiles with subscriber counts. Reads the public t.me/s preview with no login or phone number; filter by date or keyword. Channels without a preview return a status row.
Pricing
from $1.48 / 1,000 results
Rating
0.0
(0)
Developer
Axiom Works
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
6 days ago
Last modified
Categories
Share
Returns: one row per public Telegram post with channel, postId, date, text, views, viewsText, and url; optional channel profile rows.
Input: {"channels":["durov"],"maxPostsPerChannel":20}
Best for: public channel monitoring, post archives, and view-count analysis.
{"id":"telegram/460","channel":"telegram","postId":460,"date":"2026-08-26T19:12:34.000Z","views":1610000,"viewsText":"1.61M","url":"https://t.me/telegram/460"}
What does Telegram Channel Posts Scraper do?
Telegram Channel Posts Scraper collects posts from public Telegram channels through their web preview pages. Give it one or more channel usernames or t.me URLs, and it returns structured post records in an Apify dataset. Each post has a channel, canonical URL, publication date, readable text when present, original text HTML, view count, media URLs, links, and visible reaction counts. You can also request a separate channel profile record for each channel.
The Actor uses the public t.me/s/ preview. It does not sign in or read private channels, member lists, comments, or messages visible only in the Telegram app. A channel that does not expose public preview posts yields no post records; the run log reports its status. This is a batch Actor: it fetches pages, writes records, and exits. It processes up to two channels at once, paces requests within each channel, and retries block responses with backoff and fresh proxy sessions. If default datacenter proxy sessions are blocked, it tries a residential proxy when available.
The optional enrich setting classifies a post's main topic and sentiment. Enrichment sends post text to TypeSafe AI, a third-party AI processor. It costs extra per labelled post and is off by default. If the processor is unavailable or fails, the scraper continues and leaves the enrichment fields empty. Classification is an interpretation of the text, while the other post fields come from the Telegram preview.
What data can you get?
The dataset contains three record types. A post record holds one Telegram post. A channel-status record is emitted when a channel has no web preview (private, group, not found), so the run never ends silently empty. A channel record holds the public profile summary, if includeChannelInfo is enabled. Both have a stable string id (channel/postNumber), channel, url, and sourceUrl. sourceUrl identifies the exact preview page from which the record came. The channel and post number are combined to keep dataset IDs distinct when two channels use the same post number.
| Field | Record | Meaning |
|---|---|---|
id | Both | Stable ID in the form channel/postNumber, unique across channels and pages. |
recordType | Both | post, channel or channel-status. |
channel | Both | Normalized public channel username. |
url | Both | Canonical Telegram post or profile URL. |
sourceUrl | Both | Preview page that supplied the record. |
postId | Post | Telegram's post number within the channel. |
date | Post | Publication timestamp in ISO 8601 format. |
text | Post | Visible plain text with line breaks preserved as \n, when present. |
html | Post | HTML of the visible text element with inline event handlers removed, when present. |
views | Post | Numeric view count parsed from the displayed K, M, or B abbreviation. |
viewsText | Post | Original view count displayed by Telegram, such as 1.61M. |
photos | Post | Available photo URLs shown in the preview. |
video | Post | Available video URL shown in the preview. |
links | Post | Links found in the post's text. |
linkPreview | Post | Link preview URL when Telegram exposes one. |
linkPreviewTitle | Post | Title on the link preview card, when present. |
linkPreviewDescription | Post | Description on the link preview card, when present. |
linkPreviewSite | Post | Site name on the link preview card, when present. |
videoThumbnail | Post | Thumbnail image URL of the post video, when present. |
videoDuration | Post | Video length in seconds, when shown. |
author | Post | Author name shown on the post, when present. |
mediaType | Post | video, photo or link for the main media, otherwise null. |
forwardedFrom | Post | Visible attribution for a forwarded post, if shown. |
edited | Post | Whether the preview marks the post edited. |
reactions | Post | Reactions as text: the emoji (⭐ for paid stars, emoji:<id> for custom emoji) followed by the count as displayed. |
topic | Post | Optional AI classification: news, crypto, promo, tech, politics, entertainment, or other. |
sentiment | Post | Optional AI classification: positive, neutral, or negative. |
title | Channel profile | Public title of the channel. |
description | Channel profile | Public channel description. |
subscribers | Channel profile | Parsed subscriber count, when shown. |
photosCount, videosCount, linksCount | Channel profile | Parsed public profile counters, when shown. |
status | Channel profile, channel status | Whether public posts were found, or the channel status (not_found, private, no_preview). |
detail | Channel status | Why no posts were returned (private, group, not found, redirect). |
The HTML preview does not guarantee every optional field on every post. Media-only posts can have empty text. Some previews do not expose a forwarded attribution or link preview. A numeric counter can be null when its visible text cannot be parsed. The Actor preserves available media URLs but does not download images or videos.
How to use
Open the Actor's input form and enter public channel usernames, such as durov, or full https://t.me/ links. Set maxPostsPerChannel to control how far the Actor pages back through each channel, and set maxItems for a hard cap over the whole dataset. A channel profile uses one item from that total cap when profiles are enabled. Then start the Actor and open the dataset when it finishes.
The newest preview page is requested first. If more posts are needed, the Actor requests earlier pages using the smallest post number from the previous page. It deduplicates posts by stable ID. Pagination ends when the post limit is met, a page has no posts, the post numbers stop decreasing, or the selected dateFrom boundary has been passed. searchQuery uses Telegram's public channel web search; its availability depends on Telegram's preview behavior. Set dateTo to exclude newer posts while paging back into a historical window. Set afterPostIds to collect only posts newer than the saved ID for each channel. A date-only dateTo includes the full UTC day.
For a quick sample, use maxItems: 7. If the channel has at least seven available records, the dataset contains exactly seven items, counting an included profile. To receive seven posts rather than six posts plus a profile, set includeChannelInfo to false. For longer runs across many channels, increase both the per-channel limit and the global cap to the amounts you need.
Only public channels with enabled web previews can return posts. A private link, a group, or a channel without preview access cannot be made accessible by this Actor. If Telegram redirects or rejects the preview, check the run log for the channel's status. The default Apify datacenter proxy can switch to residential sessions after repeated blocks when residential access is available. Requests to Telegram are paced to roughly one per second per channel, with at most two channels active at once.
Input
| Input | Required | Default | Purpose |
|---|---|---|---|
channels | Yes | Prefilled example | Public channel usernames or t.me URLs. |
maxPostsPerChannel | No | 50 | Maximum post records for each channel, 1–1000. |
maxItems | No | 1000 | Maximum total records, including profiles, 1–10000. |
dateFrom | No | None | Earliest publication date in ISO format. |
dateTo | No | None | Latest publication date in ISO format; date-only values include the UTC day. |
afterPostIds | No | {} | Last seen numeric post ID for each channel; only newer posts are returned. |
searchQuery | No | None | Query for Telegram's public channel search. |
includeChannelInfo | No | true | Include one profile record per channel. |
enrich | No | false | Request topic and sentiment classification. |
maxJevCalls | No | 500 | Maximum AI requests per run, 1–500. |
proxyConfiguration | No | Apify datacenter proxy | Apify Proxy settings for Telegram requests. |
Example input:
{"channels": ["durov", "https://t.me/telegram"],"maxPostsPerChannel": 20,"maxItems": 42,"dateFrom": "2026-01-01","dateTo": "2026-09-30","afterPostIds": {"durov": 500},"includeChannelInfo": true,"enrich": false}
The channel list is required in API calls. The Console form shows example channels as a prefill, but an API caller must supply its own channels value. Invalid usernames, unsupported URLs, empty arrays, invalid dates, and limits outside their documented ranges fail at the start of the run with a clear error. Duplicated channel names are processed once. A URL must point to t.me; other hosts are not accepted as channel input.
Enrichment uses our third-party AI processor (TypeSafe AI); no key is needed. Post text is sent to it only when enrich is on. If the service is unavailable, records are still produced without topic and sentiment values.
Output
This channel profile record is from the local prefill run:
{"id": "durov/0","recordType": "channel","channel": "durov","url": "https://t.me/durov","sourceUrl": "https://t.me/s/durov","title": "Pavel Durov","description": "Founder of Telegram.","subscribers": 10500000,"photosCount": 102,"videosCount": 46,"linksCount": 200,"status": "ok"}
A post from the local prefill run has these values:
{"id": "telegram/460","recordType": "post","channel": "telegram","postId": 460,"date": "2026-08-26T19:12:34.000Z","text": "For all the info from today's update and a look back at 13 years of Telegram features — check out our blog:\nhttps://telegram.org/blog/welcome-messages-buttons-TG-13\n\nAugust Features\n1 • 2 • 3 • 4 • 5 • More","views": 1610000,"viewsText": "1.61M","url": "https://t.me/telegram/460","sourceUrl": "https://t.me/s/telegram"}
The sample post is shown with the fields most useful for a quick review; the Actor also stores its available HTML, media, links, reactions, and enrichment fields. Values can change as Telegram updates view and reaction counts.
How much does it cost?
Pricing is per result. Each post is charged as one result. Each channel profile record is charged as one result. Channel-status records are not charged. A post is charged an additional enrichment result only if both topic and sentiment enrichment succeeds. The final charge depends on the number of records and whether enrichment was used. See the Actor's Pricing tab for current event prices; they are intentionally not copied into this README.
Use maxItems to place a clear ceiling on the total records in a run. The maxPostsPerChannel setting controls the work for each channel, and dateFrom can stop older-page requests early. Failed AI calls do not trigger the enrichment event. Compute and proxy costs are included in the event prices.
Use with AI agents (MCP)
Apify's MCP server can expose this Actor as a tool. A client configuration can use the server URL below:
{"mcpServers": {"apify": {"url": "https://mcp.apify.com/?tools=axiomworks/telegram-channel-posts-scraper"}}}
An agent can then ask, “Collect the latest 10 posts from the public durov channel and summarize their dates and view counts.” Another prompt is, “Get public posts from telegram since 2026-01-01, and include the channel profile.” The agent should provide channels explicitly, because the Console prefill is an example rather than a value supplied to API callers. The output schema helps the agent distinguish post rows from channel profile rows.
For topic-based tasks, ask the agent to set enrich only when topic or sentiment is needed, because it costs extra per labelled post. Classification consumes an external AI service and may be incomplete. The original text, date, URL, and source URL remain available for checking a summary against its source.
Integrations and API
You can start the Actor through Apify's API and read its dataset through standard SDKs. Set your Apify API token in the APIFY_TOKEN environment variable and keep it in your application's secret store. The examples show a small public scrape; adjust the limits to suit your workflow.
Python:
import osfrom apify_client import ApifyClientclient = ApifyClient(os.environ["APIFY_TOKEN"])run = client.actor("axiomworks/telegram-channel-posts-scraper").call(run_input={"channels": ["durov"],"maxPostsPerChannel": 10,"maxItems": 10,"includeChannelInfo": False,})for item in client.dataset(run["defaultDatasetId"]).iterate_items():print(item["url"], item.get("date"))
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('axiomworks/telegram-channel-posts-scraper').call({channels: ['durov'],maxPostsPerChannel: 10,maxItems: 10,includeChannelInfo: false,});const { items } = await client.dataset(run.defaultDatasetId).listItems();for (const item of items) process.stdout.write(`${item.url}\n`);
cURL:
curl -X POST "https://api.apify.com/v2/acts/axiomworks~telegram-channel-posts-scraper/run-sync-get-dataset-items" \-H "Authorization: Bearer $APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"channels":["durov"],"maxPostsPerChannel":10,"maxItems":10,"includeChannelInfo":false}'
The synchronous endpoint is convenient for a short sample. For larger runs, start the Actor asynchronously, wait for completion, then fetch the default dataset. Dataset items can be sent onward to spreadsheets, databases, analysis jobs, or an agent. Keep id as the deduplication key if you collect the same channel repeatedly; view counts can change while that ID stays stable.
FAQ
Can this read private channels or groups? No. The Actor reads only public Telegram channel pages that expose a web preview. It has no account session and does not try to bypass login or access controls.
What happens when a channel has no public posts? The run still ends successfully. The dataset gets a channel-status record (private, not_found or no_preview) and the run status message says what to change, for example using a public channel username.
Why are there fewer posts than my limit? The public preview may have fewer accessible posts, dateFrom may exclude older posts, the channel may redirect, or Telegram may respond with an error. The Actor logs a per-channel status. The maximum is a ceiling, not a promise that a channel contains that many accessible posts.
Why does maxItems include profiles? A profile is a dataset record with its own stable ID and source URL. Counting it makes the global item limit exact. Disable includeChannelInfo when your limit should apply only to posts.
Are images downloaded? No. Photo and video fields are URLs observed in the preview. Some media URLs may be temporary or may stop working later. The Actor does not open those URLs or store binary media.
How are views and subscribers counted? Telegram displays abbreviated values such as 1.2K or 3.4M. The Actor converts them to approximate integers using decimal multipliers. The source display value can change after the run.
What happens if AI enrichment fails? Scraping continues. The relevant post is still returned, topic and sentiment remain empty, and no successful enrichment event is charged for it.
Is it legal to scrape Telegram?
This Actor is designed for publicly visible channel previews. Whether a particular use is permitted depends on your location, the content, and your intended use. Review applicable law and Telegram's terms for your case. Respect copyright, privacy, and any obligations that apply to your downstream storage or publication. The Actor does not provide access to private data or require a Telegram login. It is an independent tool and is not affiliated with Telegram.
Feedback
If a public channel's preview changes or a field stops appearing, report the channel URL, a post URL if available, the run time, and which field was missing. Avoid including secret keys or private data in a report. A reproducible public example helps identify selector changes. You can also suggest additional fields that are actually visible on the public preview. Check the run log first for redirects, rate limits, or an empty public preview.