# Telegram Channel Monitor 🔔 (keyword alerts, no login) (`tagadanar/telegram-channel-monitor`) Actor

Watch any public Telegram channel for the words you care about. Give a list of channels and keywords and get every matching message in clean JSON: text, date, views, links, hashtags and media flags. Monitor mode returns only what is new since the last run. No login, no API key.

- **URL**: https://apify.com/tagadanar/telegram-channel-monitor.md
- **Developed by:** [Tagada Data](https://apify.com/tagadanar) (community)
- **Categories:** Social media, News
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.05 / 1,000 messages

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Telegram Channel Monitor and Keyword Alerts

Watch any public Telegram channel for the words you care about. Give it a list of channels and a list of keywords and it returns every message that mentions one of them, with the text, the date, the view count, the links inside the message and what media was attached. Turn on monitor mode and each scheduled run brings back only what has been posted since the last one, which is the part TGStat and Telemetr charge a monthly subscription for.

There is no login, no phone number and no API key. It reads the same public preview page Telegram itself serves to logged-out visitors at `t.me/s/<channel>`, so nothing here depends on an account that can be banned.

### What it costs

| Event | Price |
| --- | --- |
| Message delivered | $0.0015 per message ($1.50 per 1,000) |
| Channel checked | $0.001 per channel actually read ($1.00 per 1,000) |
| Actor start | $0.001 per run |

Bronze, Silver and Gold plans get 10%, 20% and 30% off both per-item prices, so 1,000 messages from 10 channels are $1.51, or $1.06 on Gold. The start fee is flat.

Channels that turn out not to exist are never billed, and when you use keywords you only pay for the messages that actually matched. A run that finds nothing new costs you the start fee plus $0.001 per channel checked, nothing more: a daily monitor on 10 channels that has a completely quiet week costs 7.7 cents.

**Apify platform usage is included in the price** — and this actor uses **no proxy at all**, so there is nothing else to pay: no compute line, no proxy line, no subscription, no API key.

### What you get

One record per message (`recordType: "message"`):

| Field | Description |
| --- | --- |
| `channel`, `channelUsername`, `channelTitle` | The channel as you typed it, its real Telegram username, and its display name |
| `messageId`, `postId`, `url` | The message number, the `channel/id` pair, and a direct link to the post |
| `date` | When it was posted, ISO 8601 with the timezone |
| `text`, `textLength` | The message text with its line breaks kept, markup stripped |
| `matchedKeywords` | Which of your keywords this message hit |
| `views`, `viewsText` | View count as a number (`1600000`) and as Telegram prints it (`1.6M`) |
| `authorName` | The signature on the post, when the channel signs its posts |
| `hasMedia`, `mediaTypes`, `isAlbum` | Whether something is attached, and what: photo, video, video\_note, voice, audio, document, sticker, poll, location |
| `links`, `hashtags`, `mentions` | Every link in the message, plus its hashtags and @mentions, lower-cased |
| `linkPreviewUrl`, `linkPreviewTitle`, `linkPreviewSite` | The link card Telegram rendered under the post |
| `isForwarded`, `forwardedFrom`, `forwardedFromUrl` | Where a forwarded post came from |
| `isReply`, `replyToUrl` | The post this one replies to |
| `isNewSinceLastRun`, `isBaseline` | Monitor mode only: whether this is a fresh post or part of the first snapshot |
| `scrapedAt` | Run timestamp |

And one summary per channel (`recordType: "channel"`):

| Field | Description |
| --- | --- |
| `title`, `description`, `isVerified` | The channel's name, its bio and whether Telegram verified it |
| `subscribers`, `subscribersText` | Subscriber count as a number and as shown |
| `photosCount`, `videosCount`, `filesCount`, `linksCount` | What the channel has posted overall |
| `status`, `statusDetail` | `ok`, `empty`, `restricted` or `notfound`, and a sentence saying why |
| `messagesFetched`, `messagesDelivered`, `pagesFetched` | What the run read and what it billed |
| `lastMessageId`, `previousLastMessageId` | Monitor mode: where the watch stands now and where it stood before |

Media is reported, not downloaded: you get to know that a post carried a video without paying to transfer it.

### Who uses it

Brand and PR teams watching for their company name in the channels where a story breaks before it reaches the press. Crypto and trading desks following token and project channels for announcements. OSINT and research teams tracking a set of channels over months without a personal account in the loop. Newsrooms watching official channels for statements. Sales teams pulling leads out of niche job, deal or classified channels.

### Input examples

Watch two channels for the words that matter, most recent 50 messages each:

```json
{
  "channels": ["telegram", "durov"],
  "keywords": ["update", "premium"],
  "maxMessagesPerChannel": 50
}
```

A daily alert feed: schedule this and every run after the first returns only what is new.

```json
{
  "channels": [
    "https://t.me/telegram",
    "@durov"
  ],
  "keywords": ["outage", "security"],
  "onlyNewSinceLastRun": true,
  "maxMessagesPerChannel": 200,
  "slackWebhookUrl": "https://hooks.slack.com/services/T000/B000/xxxx"
}
```

Everything a channel has posted in the last week, no keyword filter:

```json
{
  "channels": ["toncoin"],
  "sinceDays": 7,
  "maxMessagesPerChannel": 500
}
```

### How monitor mode works

The first run with `onlyNewSinceLastRun` on gives you the current picture and remembers the newest message it delivered for each channel. Every run after that starts at that mark and stops as soon as it reaches it, so a channel with nothing new costs one page fetch. Adding or removing a channel from the list does not disturb the others: each channel keeps its own position.

If a run is cut short by a charge limit, the messages it did not deliver are not marked as seen, so they come back as new next time rather than being lost.

### Questions people ask

**Do I need a Telegram account or a phone number?**
No. This reads the public preview page that Telegram serves to anyone, so there is no session, no login and no account to keep alive.

**Can it read private or invite-only channels?**
No, and it will say so instead of returning nothing. A `t.me/+…` or `joinchat` link is skipped with a note in the run's status message. There is no way to read a private channel without being a member, and this actor does not use member accounts.

**Some channels come back with status `restricted`. Why?**
Public groups, bots and a few channels whose owners switched the web preview off do not serve a message list at `t.me/s/`. The run tells you which ones and what they are, rather than quietly returning zero.

**How far back can it go?**
As far as the channel's own history goes, up to 8,000 messages per channel in a single run. Telegram serves 20 messages per page and this actor pages backwards through them, so `maxMessagesPerChannel: 2000` reads 100 pages. Use `sinceDays` when you want a date window instead of a count, and schedule repeated runs if you need to walk a very long history.

**How does keyword matching work?**
Case-insensitive, and it looks at the message text, its hashtags, its mentions, the title of any link card and the links themselves. A keyword can be a phrase. Leave the list empty to get every message.

**Does it download photos and videos?**
No. It reports what is attached (`hasMedia`, `mediaTypes`) so you can filter on it, and links to the post if you want to open it yourself.

**Is this a TGStat or Telemetr alternative?**
For monitoring, yes: keyword watching across a list of channels, on a schedule, exported as JSON, CSV or Excel, and paid per message instead of per month. It does not do the audience analytics or the channel-discovery search those tools sell.

**A run stopped early and said it hit a page budget. What is that?**
Reading pages is what the run costs; delivering matches is what it bills. If a keyword search reads hundreds of pages without matching much, the run stops rather than keep going, and says so in its status message. Narrow the channel list, widen the keywords, or add `sinceDays` and it will not come up.

**What happens to a channel name I typed wrong?**
It comes back as `status: "notfound"` with an explanation, and you are not charged for it. The run still succeeds and the other channels still run.

### Related actors

- [Threads Scraper](https://apify.com/tagadanar/threads-scraper) for the same job on Threads.
- [Brand News Monitor](https://apify.com/tagadanar/brand-news-monitor) when the mention you are watching for is in the press rather than in a channel.
- [LinkedIn Hiring Signals Monitor](https://apify.com/tagadanar/linkedin-hiring-signals-monitor) for the same new-since-last-run pattern on LinkedIn job postings.

***

Keywords: telegram scraper, telegram channel scraper, telegram monitor, telegram keyword alerts, telegram message scraper, scrape telegram without login, telegram channel posts export, telegram osint, telegram brand monitoring, tgstat alternative, telemetr alternative, t.me scraper.

# Actor input Schema

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

One entry per public channel. A name (<code>telegram</code>), a handle (<code>@telegram</code>) or a link (<code>https://t.me/telegram</code>) all work. Private and invite-only channels (<code>t.me/+…</code>, <code>joinchat</code>) have no public page and are skipped with a note.

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

Leave empty to get every message. Give words or phrases and you only get (and only pay for) messages that mention one of them. Matching is case-insensitive and looks at the message text, its hashtags, its @mentions and its links.

## `maxMessagesPerChannel` (type: `integer`):

How far back to read in each channel, newest first. Telegram serves 20 messages per page, so 500 here means 25 pages. You are only charged for messages actually delivered.

## `sinceDays` (type: `integer`):

Stop reading once messages get older than this many days. Leave at 0 for no date limit.

## `onlyNewSinceLastRun` (type: `boolean`):

Turn this on and schedule the run: the first run gives you the current picture, every run after that returns only messages that were not there before. The position in each channel is remembered between runs.

## `slackWebhookUrl` (type: `string`):

Paste a Slack incoming-webhook URL to also get a short digest of what the run found posted to a channel. Never charged.

## Actor input object example

```json
{
  "channels": [
    "telegram",
    "durov"
  ],
  "keywords": [],
  "maxMessagesPerChannel": 30,
  "sinceDays": 0,
  "onlyNewSinceLastRun": false
}
```

# Actor output Schema

## `messages` (type: `string`):

One item per message, plus one summary item per channel, in the default dataset.

# 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": [
        "telegram",
        "durov"
    ],
    "keywords": [],
    "maxMessagesPerChannel": 30
};

// Run the Actor and wait for it to finish
const run = await client.actor("tagadanar/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": [
        "telegram",
        "durov",
    ],
    "keywords": [],
    "maxMessagesPerChannel": 30,
}

# Run the Actor and wait for it to finish
run = client.actor("tagadanar/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": [
    "telegram",
    "durov"
  ],
  "keywords": [],
  "maxMessagesPerChannel": 30
}' |
apify call tagadanar/telegram-channel-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tagadanar/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/bHkn0ms0JcoLpZmJV/builds/U9e4FN73HJ48Tbzaf/openapi.json
