Telegram Channel Scraper & Keyword Search: posts, views, media

Scrape any public Telegram channel with no login or API key: messages with text, dates, views, reactions, media URLs, forwards, polls and link previews, plus subscriber counts. Keyword search inside channels, date windows, and a changes-only monitor for scheduled Slack/email alerts. Pay per message.

Run on Apify Pricing API docs

Categories: SOCIAL_MEDIA, NEWS, AGENTS. Pay per result, no subscription; Apify's free plan includes $5 of monthly usage.

Run it from the command line

curl -sS -X POST "https://api.apify.com/v2/acts/brenton8907~telegram-channel-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"channels": ["durov", "bloomberg"], "maxMessagesPerChannel": 100, "includeChannelInfo": true, "includeHtml": false, "changesOnly": false, "monitorStoreName": "telegram-channel-monitor"}'

Run it from Python

from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("brenton8907/telegram-channel-scraper").call(run_input={
  "channels": [
    "durov",
    "bloomberg"
  ],
  "maxMessagesPerChannel": 100,
  "includeChannelInfo": true,
  "includeHtml": false,
  "changesOnly": false,
  "monitorStoreName": "telegram-channel-monitor"
})
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

Use it as an MCP tool (Claude, Cursor, any MCP client)

The actor is listed in the official MCP registry as io.github.brenton-keller/telegram-channel-scraper and served by Apify's hosted MCP server:

{
  "mcpServers": {
    "telegram-channel-scraper": {
      "url": "https://mcp.apify.com/?tools=brenton8907/telegram-channel-scraper",
      "headers": {
        "Authorization": "Bearer YOUR_APIFY_TOKEN"
      }
    }
  }
}

Pricing (pay per event)

eventwhatpricedetails
message-recordMessage$0.0010One channel post: text, date, views, reactions, media URLs, forwards, replies, poll, link preview, hashtags, mentions.
channel-recordChannel info$0.0020One channel row: title, description, subscriber count, photo/video/file/link counts, avatar URL.

Documentation

Scrape any public Telegram channel without a login, a phone number, or API keys, and search channels by keyword using Telegram's own in-channel search. Reads Telegram's own public web preview (t.me/s/<channel>), so it needs no browser, no proxies and no session, and it does not break when the Telegram app changes. Returns the full post history as flat rows, plus one channel-info row with the subscriber count. Includes a changes-only monitor mode so a scheduled run gives you only what was posted since last time.

Try it free: every Apify account includes free monthly usage; 1,000 messages cost $1, so a first run costs nothing.

Keyword search across channels

Search many channels for the terms you care about without downloading their full history. The actor uses Telegram's in-channel search (t.me/s/<channel>?q=), one request per keyword per page of 20 results, so 20 channels × 3 keywords is about 60 requests and you pay only for the posts that match.

{
  "channels": ["bloomberg", "cryptosignals", "telegram", "durov"],
  "keywords": ["airdrop", "listing", "ETF"],
  "maxMessagesPerChannel": 50,
  "includeChannelInfo": false
}

Every row has matched_keyword, so you know which term found it. The actor reads keyword result streams round-robin, splitting maxMessagesPerChannel fairly across terms instead of letting a high-volume first keyword fill the whole cap. Set the cap at least as high as the number of terms. Combine with sinceDate to search only recent posts. Search is per channel (Telegram has no public cross-channel search); give the actor the channel list you want covered.

Channel monitor: schedule it, get new posts in Slack or email

Turn any set of channels into an alert feed. Three steps, no code:

  1. Create a task from this actor with the input below and run it once. The first run seeds the newest message ID per channel.
  2. Schedule it (task → Schedule, or Console → Schedules): every 15 minutes, hourly or daily. A quiet channel costs one request and no result charges, so frequent polling is cheap.
  3. Alerts: in the task's Integrations tab add Slack or Gmail on "run succeeded". The run's status message is written for this: 12 NEW post(s) since last run across 3/3 channel(s) or No new posts since last run. Slack template (Handlebars):

*Telegram monitor:* {{resource.statusMessage}} <https://console.apify.com/storage/datasets/{{resource.defaultDatasetId}}|Open the new posts>

To notify only when something is new, or to forward the post text itself, route the run through n8n / Make / Zapier (Apify triggers exist for all three) and filter on the dataset items.

{
  "channels": ["cryptosignals", "telegram", "bloomberg"],
  "changesOnly": true,
  "monitorStoreName": "signals-watch",
  "includeChannelInfo": false
}

Add keywords to the same input to get alerts only for posts that mention your terms. Cost at scale: 20 channels posting 30 new messages a day in total = $0.03/day, under $1/month.

What it does

Who it's for

Input examples

Latest 100 posts from two channels, with channel info (default):

{ "channels": ["durov", "https://t.me/bloomberg"] }

Everything a channel posted in January 2026:

{ "channels": ["telegram"], "sinceDate": "2026-01-01", "untilDate": "2026-01-31", "maxMessagesPerChannel": 5000 }

Only posts mentioning specific terms, newest 50 per term:

{ "channels": ["bloomberg"], "keywords": ["oil", "Fed"], "maxMessagesPerChannel": 50, "includeChannelInfo": false }

Monitor (see the section above): the first run with changesOnly: true outputs the latest maxMessagesPerChannel posts and seeds the store; later runs output only newer posts. Use a different monitorStoreName per watchlist.

Fetch only what is newer than a message you already have:

{ "channels": ["durov"], "sinceMessageId": 540 }

Output

One row per message; with includeChannelInfo also one row per channel.

Field Description
channel, channel_title Channel username and display title
message_id, url Numeric post ID (increasing) and https://t.me/<channel>/<id>
date Posted time, ISO 8601 UTC
text Plain text with line breaks; text_html when includeHtml is on
author Author signature, when the channel shows one
views View count as an integer (Telegram shows "1.2M"; we return 1200000)
reactions, reactions_total [{ "emoji", "count", "custom_emoji_id"?, "paid"? }] and the sum
is_edited, is_service Edited flag; service messages (pinned, channel created, etc.)
forwarded_from { "name", "url", "author" } or null
reply_to { "message_id", "url", "author", "text", "thumbnail_url" } or null
media, media_types [{ "type", "url", "thumbnail_url", "duration", "title", ... }]; types: photo, video, gif, round_video, document, sticker, voice, audio
link_preview { "url", "site_name", "title", "description", "image_url" } or null
poll { "question", "type", "options": [{ "text", "percent" }], "votes" } or null
links, hashtags, mentions Extracted from the text
matched_keyword Only with keywords: which search term returned this post
is_new Only in monitor mode
scraped_at When the row was fetched (UTC)

Channel row: username, url, title, description, subscribers, photos_count, videos_count, files_count, links_count, photo_url, messages_scraped, scraped_at.

Media URLs point at Telegram's CDN. Video URLs carry a token and expire after some hours; download them in the same workflow if you need to keep them.

Pricing

Pay per result. You are charged only for rows written to the dataset; error rows are free.

Event Price When
Message $1.00 per 1,000 messages Every message row
Channel info $2.00 per 1,000 channels One row per channel when includeChannelInfo is on

Examples: the latest 1,000 posts from a channel cost $1.00. A monitor run over 20 channels that finds 12 new posts costs $0.012. The first monitor run charges every post it seeds with, like any other run.

Set Maximum total charge on the run to cap spend; the actor stops cleanly at the cap.

Limits and notes

Use from an AI agent (MCP)

Every Apify actor is available as a tool through the Apify MCP server. Add it to Claude, Cursor, or any MCP client and call this actor by name with the JSON input above. Suggested agent pattern: keep a watchlist, run with changesOnly: true on a schedule, and act only on the rows returned.

Support

Open an issue on the actor page with the run ID and input. If Telegram changes its preview markup, affected fields go null rather than failing the run; report which field and we will patch it. If the actor saved you time, a review helps other people find it.