# Telegram Channel Scraper & Monitor: Posts, Views, Reactions (`developing_developer/telegram-channel-monitor`) Actor

Scrape posts from public Telegram channels: text, date, views, reactions, hashtags, links, photos and channel subscribers. Search inside channels, filter by keyword and date, and use monitor mode to get only new posts. No login, no API key.

- **URL**: https://apify.com/developing_developer/telegram-channel-monitor.md
- **Developed by:** [Đăng lê](https://apify.com/developing_developer) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Telegram Channel Scraper & Monitor: Posts, Views, Reactions

Get posts from any **public Telegram channel**, or **search a keyword across thousands of active public channels** at once: full text, date, views, reactions, engagement rate, hashtags, links, photos, video thumbnails, link previews, forwards and replies, plus the channel's title and subscriber count. **Find channels** by keyword, topic and language. Turn on **monitor mode** to receive only the posts published since your last run.

The Actor reads the public web preview that Telegram serves for every public channel at `t.me/s/<channel>`. No login, no phone number, no API key, no Telegram account.

### What you get

- **Search all channels**: run Telegram's own search for your keyword in every channel of the built-in directory of active public channels, narrowed by language, topic and size. Combine it with monitor mode for keyword alerts across Telegram.
- **Find channels**: list channels by keyword, topic and language with subscribers, description and last post date. Or look up live details of the channels you list.
- **Every post field that matters**: text (and optional HTML), date, edited flag, views, reactions with counts (including paid Star reactions), engagement rate, views per subscriber, hashtags, links, media types, photo URLs, video thumbnails, link preview (site, title, description), forwarded-from and reply-to.
- **Channel details on every post**: channel username, title and subscriber count, so you can rank posts by reach.
- **Search inside channels**: `searchQuery` uses Telegram's search on each channel, so you can reach older posts about a topic without reading the whole history.
- **Monitor mode**: schedule the Actor and get only new posts. Quiet runs return nothing and cost only the $0.001 run fee.
- **Filters**: keywords, excluded words, posted within N days, max posts per channel.
- **Clear run summary**: channel title, description, subscribers and verified badge; channels without a public preview; posts scanned and returned.

### Use cases

- Track crypto, finance or news channels and react to new announcements within minutes.
- Monitor competitors, brands or product channels for launches and price changes.
- Feed new posts to Slack, email, Google Sheets or an AI agent through Apify integrations.
- Build datasets for research, sentiment analysis or media monitoring.
- Compare channels by views and reactions per post.

### Input

| Field | Description |
|---|---|
| `mode` | `posts` (default) or `channels` (find channels in the directory, or look up the channels you list). |
| `channels` | Public channels: `durov`, `@durov`, `https://t.me/durov`, `t.me/s/durov` or a post link such as `https://t.me/durov/552`. |
| `searchQuery` | Posts: Telegram's search inside each channel, e.g. `TON` or `#update`; leave empty to read the latest posts. Channels: words that must appear in the channel name, title or description. |
| `searchAllChannels` | Search `searchQuery` in the directory channels too (requires `searchQuery`). |
| `languages`, `topics`, `minSubscribers`, `maxChannels` | Narrow the directory channels. `maxChannels` (default 1,000) keeps the largest matching channels. |
| `keywords` | Keep posts whose text, hashtags or link preview title contain any of these words. |
| `excludeKeywords` | Drop posts that contain any of these words. |
| `postedWithinDays` | Only posts from the last N days. Reading stops at the first older post. |
| `maxPostsPerChannel` | How many of the newest posts (or search results) to read per channel. Default 100; 0 = all posts, up to 10,000 per channel. |
| `includeHtml` | Add the formatted text as HTML in `textHtml`. |
| `onlyNewPosts` + `monitorName` | Monitor mode. The first run returns the latest posts and remembers the newest one per channel; later runs return only newer posts. |

Latest 50 posts from two channels:

```json
{
  "channels": ["durov", "https://t.me/telegram"],
  "maxPostsPerChannel": 50
}
```

Every post about TON on a channel:

```json
{
  "channels": ["durov"],
  "searchQuery": "TON",
  "maxPostsPerChannel": 0
}
```

Every English-language post about airdrops in the last 7 days, across the English crypto channels in the directory:

```json
{
  "searchAllChannels": true,
  "searchQuery": "airdrop",
  "languages": ["en"],
  "topics": ["crypto"],
  "postedWithinDays": 7
}
```

Hourly alerts when any channel in the directory mentions your brand (run it on a schedule):

```json
{
  "searchAllChannels": true,
  "searchQuery": "YourBrand",
  "onlyNewPosts": true,
  "monitorName": "brand-alerts"
}
```

Find the largest Spanish-language news channels:

```json
{
  "mode": "channels",
  "languages": ["es"],
  "topics": ["news"],
  "maxChannels": 50
}
```

Daily feed of new posts that mention a keyword (run it on a schedule):

```json
{
  "channels": ["tginfo", "telegram", "durov"],
  "keywords": ["update", "wallet"],
  "onlyNewPosts": true,
  "monitorName": "telegram-updates"
}
```

### Output

```json
{
  "id": "durov/548",
  "channel": "durov",
  "channelTitle": "Pavel Durov",
  "channelSubscribers": 10200000,
  "postId": 548,
  "url": "https://t.me/durov/548",
  "date": "2026-09-11T16:04:02.000Z",
  "edited": false,
  "text": "🤝 Telegram has become the sponsor of Codeforces — the largest competitive progra...",
  "views": 3740000,
  "reactions": [
    { "emoji": null, "emojiId": null, "paid": true, "count": 21900 },
    { "emoji": null, "emojiId": "5399847211989246390", "paid": false, "count": 36500 },
    { "emoji": null, "emojiId": "5936157098181135162", "paid": false, "count": 10700 },
    { "emoji": null, "emojiId": "5373223594484587136", "paid": false, "count": 10000 }
  ],
  "reactionsTotal": 79100,
  "engagementRate": 0.0211,
  "viewsPerSubscriber": 0.3667,
  "hashtags": [],
  "links": ["https://codeforces.com/blog/entry/156620"],
  "mediaTypes": [],
  "photoUrls": [],
  "videoThumbnailUrls": [],
  "linkPreview": {
    "url": "https://codeforces.com/blog/entry/156620",
    "siteName": "Codeforces",
    "title": "Telegram Returns as Title Sponsor of Codeforces!",
    "description": "Hi, Codeforces!"
  },
  "forwardedFrom": null,
  "replyToPostId": null,
  "scrapedAt": "2026-10-27T08:22:30.354Z"
}
```

`engagementRate` is reactions divided by views; `viewsPerSubscriber` is views divided by the channel's subscribers. `mediaTypes` can contain `photo`, `video`, `round_video`, `voice`, `audio`, `document`, `sticker`, `poll` and `location`. Fields Telegram does not show are `null` or empty; nothing is guessed. The run summary is saved to the `SUMMARY` record in the key-value store.

In `channels` mode each item is a channel:

```json
{
  "username": "cointelegraph",
  "url": "https://t.me/cointelegraph",
  "title": "Cointelegraph",
  "description": "The Future of Money\n\nUnbiased crypto, markets & Web3 news in real-time. Trusted since 2013. ...",
  "subscribers": 328000,
  "verified": false,
  "photoUrl": null,
  "language": "en",
  "topics": ["news", "crypto", "finance"],
  "lastPostDate": "2026-10-27T05:18:37.000Z",
  "source": "directory",
  "scrapedAt": "2026-10-27T09:31:42.775Z"
}
```

`source` is `directory` for channels from the built-in directory (built date in `SUMMARY`) and `live` for channels you listed, which are read from Telegram during the run (and include `photoUrl`).

### Channel directory

The directory contains active public channels (at least 1,000 subscribers and a post in the last 120 days), discovered by following links and forwards between public channels. Adult channels are excluded.

Built on 27 October 2026: **8,353 channels**, 701 of them with 100,000+ subscribers and 3,641 with 10,000+. By language: 7,356 Russian, 298 English, 264 German, 134 Ukrainian, 72 Italian, 49 French, 41 Spanish, 34 Kazakh and a few others. Russian-language Telegram is by far the largest network of public channels and is covered in depth; the English part covers the major crypto, news, geopolitics, finance and tech channels. For other markets, list the channels you need in `channels`. Language and topics are detected from each channel's title, description and recent posts, so they are approximate. Topics: crypto, finance, news, politics, tech, ai, business, sports, gaming, entertainment, education, jobs, travel, health, science, deals.

Channels you list in `channels` are always included, even when they are not in the directory.

### Pricing

You pay per result: **$1.00 per 1,000 posts or channels** ($0.001 per result) plus $0.001 per run. Platform usage is included: you never pay for compute time, even when searching thousands of channels.

| Example | Posts returned | Cost |
|---|---|---|
| Latest 100 posts from 5 channels | 500 | $0.501 |
| Hourly monitor of 10 channels, a quiet hour | 0 | $0.001 (about $0.72 per month) |
| Daily monitor of 10 channels with 30 new posts | 30 | $0.031 |
| Search a keyword in 1,000 channels, 40 matching posts | 40 | $0.041 |
| Find the 100 largest channels on a topic | 100 channels | $0.101 |

Posts removed by your filters and posts already returned in monitor mode are free.

### Notes

- Only public channels have a web preview. Private channels, groups, bots, user accounts and invite links (`t.me/+...`) are listed in `SUMMARY` under `channelsWithoutPublicPage` or `invalidEntries` and skipped.
- Views, reactions and subscribers are the rounded numbers Telegram shows (`1.54M` becomes `1540000`).
- Reactions with custom or animated emoji have only `emojiId`; Telegram's preview does not show the emoji character for them.
- Photo and video URLs point to Telegram's CDN and expire after some time. Download them soon if you need to keep them.
- Comments under posts are not part of the public preview and are not included.
- In monitor mode, `maxPostsPerChannel` still applies: if a channel publishes more new posts than that between two runs, only the newest ones are returned. Raise it or run more often for very active channels.
- Signed post author names are not extracted.

### FAQ

**Is this legal?** The Actor reads only the public web preview that Telegram shows to anyone at `t.me/s/<channel>`, at a polite pace. It does not log in, join channels or collect members' personal data.

**Why did a channel return nothing?** Check `SUMMARY`: the name may be a group, bot, user or private channel without a public preview, or a typo.

**Can I search all of Telegram?** Telegram has no public search across all channels. "Search all channels" searches every channel in the built-in directory of active public channels, which covers the large and active ones. Add the channels you care about in `channels` to be sure they are searched.

**Can I get the full history of a channel?** Set `maxPostsPerChannel` to `0`. The Actor reads up to 10,000 posts per channel, 20 posts per page.

**How do I get alerts?** Turn on `onlyNewPosts`, schedule the Actor (for example every hour) and connect the dataset to Slack, email, Make, Zapier or a webhook.

# Actor input Schema

## `mode` (type: `string`):

Posts: posts from channels (your list, or every channel in the directory with "Search all channels"). Channels: find channels by keyword, language and topic, or look up details of the channels you list.

## `channels` (type: `array`):

Public Telegram channels: username ("durov", "@durov") or link ("https://t.me/durov", "t.me/s/durov", a post link). Private channels, groups, bots and invite links (t.me/+...) have no public web preview and are skipped. Optional when "Search all channels" is on or when finding channels.

## `searchQuery` (type: `string`):

Posts: Telegram's own search inside each channel, e.g. "TON" or "#update" (required for "Search all channels"). Channels: words that must appear in the channel name, title or description.

## `searchAllChannels` (type: `boolean`):

Search the query in every channel of the built-in directory of active public channels (largest first), narrowed by the filters below. Combine with monitor mode to get alerts when any channel mentions your keyword.

## `languages` (type: `array`):

Directory channels only: ISO codes such as "en", "es", "ru". The language is detected from channel content and is approximate.

## `topics` (type: `array`):

Directory channels only: keep channels with any of these topics (detected from channel content, approximate).

## `minSubscribers` (type: `integer`):

Directory channels only.

## `maxChannels` (type: `integer`):

How many matching directory channels to use, largest first. Default 1,000.

## `keywords` (type: `array`):

Keep posts whose text, hashtags or link preview title contain at least one of these words (case-insensitive).

## `excludeKeywords` (type: `array`):

Drop posts that contain any of these words.

## `postedWithinDays` (type: `integer`):

Only posts from the last N days. Reading stops at the first older post. 0 = no date limit.

## `maxPostsPerChannel` (type: `integer`):

How many of the newest posts (or search results) to read per channel. 0 = all posts, up to 10,000 per channel.

## `includeHtml` (type: `boolean`):

Add the post text as HTML (bold, links, quotes) in textHtml.

## `onlyNewPosts` (type: `boolean`):

Return only posts published after the newest post seen by earlier runs with the same monitor name. The first run returns the latest posts and saves the position. Use with a schedule to get a feed of new posts.

## `monitorName` (type: `string`):

Separate monitors keep separate positions. Use letters, numbers and hyphens.

## Actor input object example

```json
{
  "mode": "posts",
  "channels": [
    "durov",
    "telegram"
  ],
  "searchAllChannels": false,
  "minSubscribers": 0,
  "maxChannels": 1000,
  "postedWithinDays": 0,
  "maxPostsPerChannel": 100,
  "includeHtml": false,
  "onlyNewPosts": false,
  "monitorName": "default"
}
```

# Actor output Schema

## `results` (type: `string`):

One item per post with text, date, views, reactions, media and links.

## `summary` (type: `string`):

Channel title, subscribers and description, channels without a public page, posts scanned and returned.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "channels": [
        "durov",
        "telegram"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("developing_developer/telegram-channel-monitor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "channels": [
        "durov",
        "telegram",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("developing_developer/telegram-channel-monitor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "channels": [
    "durov",
    "telegram"
  ]
}' |
apify call developing_developer/telegram-channel-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,developing_developer/telegram-channel-monitor"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/zfU9c2oBXgrCSM1ci/builds/n3mtWeG0fBzAbWbGy/openapi.json
