# Telegram Channel Scraper & Monitor - Posts, Comments, API, MCP (`akhil_rajesh/telegram-channel-scraper`) Actor

Telegram channel scraper and monitor without login: scrape Telegram posts, views, reactions, media, comments and exact subscriber counts. Telegram keyword alerts and channel search: new, edited and deleted posts to Slack, Discord or Teams. Telegram API and MCP server for AI agents.

- **URL**: https://apify.com/akhil_rajesh/telegram-channel-scraper.md
- **Developed by:** [Akhil rajesh](https://apify.com/akhil_rajesh) (community)
- **Categories:** Social media, News, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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?

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

Scrape **public Telegram channels without a login**: every post's **text, date, views, reactions** (each emoji's count, and paid stars), **photos, videos, voice notes, files and stickers**, **polls**, **link previews**, links, hashtags and mentions, and what a post **forwards or replies to**. Read a channel's **history back by date**, search it with **Telegram's own search**, read the **comments** under each post, and get each channel's **exact subscriber count**, description and posting pace.

**One price, no extras: $1.00 per 1,000 results, with platform usage included and no row cap on Apify's free plan.** (Apify's Store page lists platform usage too, because the live API below adds its own; ordinary runs never do.)

It is also a **Telegram channel monitor**. Schedule it with **Only changes** and each run returns only what moved since the last one: **new posts, edited posts (with the text before the edit) and deleted posts**, plus the **change in subscribers**, posted to **Slack, Discord or Microsoft Teams** if you like. It runs as a **live API and MCP server** for AI agents too.

### Why this scraper

- **No login, no phone number, no session to lose.** It reads Telegram's own public web preview (t.me/s/\<channel>), the page anyone can open. Scrapers that log in to Telegram break when their account is limited or banned; this one has no account.
- **It tracks changes, not just posts.** Most Telegram scrapers return the same posts every run. This one keeps a history per channel and returns new posts, edits (what the text said before) and deletions, each once. A post missing from a channel is checked on its own page first: Telegram's "Post not found" reports it deleted at once.
- **Exact subscriber counts.** The preview rounds them ("9.23M"); each channel row reads the exact count from the channel's own page (9,230,249), and with Only changes, the change since the last run.
- **Comments too.** Up to 100 comments per post, with the commenter, text, time and what each replies to, from Telegram's own comments widget.
- **Search a channel, or its whole history.** Telegram's own search finds the newest matches fast; Only posts containing reads the channel back as far as you like and filters it.
- **Says what it can't read.** A group, a person, a bot, a private invite link, or a channel whose owner turned its preview off gets a free row saying which.

| | Typical Telegram channel scrapers | This Actor |
|---|---|---|
| Login, phone or session needed | Some (and they break when the account is limited) | Never |
| New, edited and deleted posts since the last run | You compare runs yourself | Built in (Only changes), with the text before an edit |
| Alerts to Slack, Discord, Teams | Rare | Yes |
| Exact subscriber count and its change | Rounded count | Exact, with the change since the last run |
| Comments | Rare | Up to 100 per post |
| Reactions per emoji, paid stars, polls, albums | Some | Yes |
| MCP server for AI agents | Rare | Its own |
| Price per 1,000 results | About $1 to $10, some plus a fee per run or per channel | $1.00, less on paid plans |

### Use cases

- **News and market monitoring**: a schedule every 15 minutes on crypto, finance or news channels that posts each new post to Slack or Discord.
- **Brand and keyword watch**: Search terms or Only posts containing on the channels of your market, every hour.
- **Deleted and edited posts**: catch a post a channel edited or deleted, with what it said before (OSINT, journalism, compliance).
- **Channel analytics**: subscribers, posting pace, average views and reach for a list of channels, tracked over time.
- **Research datasets**: a channel's whole history back to a date, with views, reactions and media.
- **AI agents**: ask an assistant "what did @durov post this week, and how many views did it get?" through the MCP server.

### How to use it in 4 steps

1. Add **Channels**: usernames such as `durov` or `@telegram`, or links such as `https://t.me/s/WatcherGuru`. A post link (`t.me/durov/400`) reads that post.
2. Set **Max posts per channel**, and **Posted after** for a date range (`2026-10-01` or `7 days`).
3. Add **Search terms** or **Only posts containing** if you want matches only, and **Comments per post** if you want comments. Run it.
4. To monitor, switch on **Only changes since the last run**, add an **Alert webhook URL** if you want chat alerts, and schedule it.

### What you get

One row per post (`type: "post"`). Example (a real row, an album post of Watcher Guru, 2026-10-27; text and links shortened):

```json
{
    "type": "post",
    "channel": "WatcherGuru",
    "channelTitle": "Watcher Guru",
    "channelId": 1556054753,
    "postId": 15638,
    "url": "https://t.me/WatcherGuru/15638",
    "date": "2026-10-27T15:59:20Z",
    "text": "JUST IN: 🇨🇳 China's tech stock index \"STAR 50\" has now crashed 40% since June as bear market continues. ...",
    "views": 81500,
    "viewsText": "81.5K",
    "reactions": [{"emoji": "❤", "count": 307}, {"emoji": "🤯", "count": 192}, {"emoji": "🔥", "count": 100},
                  {"emoji": "🤣", "count": 75}, {"emoji": "😢", "count": 38}],
    "reactionsTotal": 712,
    "paidStars": 1,
    "media": [{"type": "photo", "url": "https://cdn4.telesco.pe/file/...", "postUrl": "https://t.me/WatcherGuru/15638?single"},
              {"type": "photo", "url": "https://cdn4.telesco.pe/file/...", "postUrl": "https://t.me/WatcherGuru/15639?single"}],
    "albumPostIds": [15638, 15639],
    "mediaTypes": ["photo"],
    "imageUrl": "https://cdn4.telesco.pe/file/...",
    "mentions": ["WatcherGuru"],
    "scrapedAt": "2026-10-28T21:13:59Z"
}
```

Every post row has its channel, id, link and date, the text with its line breaks, views, reactions, and as it applies: `media` (photos, videos, GIFs, voice notes, round videos, files, audio, stickers, locations, with links and durations), `poll` (question, options with their percentages, voters), `linkPreview`, `links`, `hashtags`, `mentions`, `buttons`, `forwardedFrom`, `replyTo`, `author` (a signed post), `isEdited`, and `albumPostIds` for an album.

A **channel row** (`type: "channel"`, once per channel a run, with Channel details on): name, `subscribers` (exact, from the channel's page), `description`, `verified`, avatar, the preview's photo, video, link and file counts, the newest post's id and date, `postsPerDay`, `averageViews` and `viewsPerSubscriber` of its newest posts, and with Only changes `previousSubscribers` and `subscribersChange`.

A **comment row** (`type: "comment"`, with Comments per post): the channel and post, `commentId`, `authorName`, `authorUsername` (when public), `text`, `date`, `replyToCommentId` and `replyToAuthor`, and its link.

**Numbers**: Telegram's preview rounds views and reactions past 999 to three digits ("34.6K"), so `views` is that rounding (34,600) and `viewsText` what the page showed; subscriber counts on channel rows are exact. **Media links** come from Telegram's servers with an access token and stop working after a while: download what you need soon after the run.

With **Only changes**, each post row also has `change`:

| change | meaning |
|---|---|
| `newPost` | a post published since the last run |
| `edited` | the post's text, media or poll changed; `previousText` is its text before, `textChanged` says whether the text or only the media changed |
| `deleted` | the post left the channel; `deletionConfirmed` is true when its own page answered "Post not found" |
| `firstRun` | the first run's baseline: the newest posts there now |

The dataset has views for **Posts**, **Changes**, **Engagement**, **Media**, **Comments**, **Channels** and **Not found** (a view picks columns: every view lists every row, so filter on `type` or `change` if you need to).

### How to use it

#### Channels

A channel is its username (`durov`, `@telegram`) or any link to it (`t.me/durov`, `https://t.me/s/durov`, `telegram.me/durov`, `tg://resolve?domain=durov`). A **post link** (`https://t.me/durov/400`) reads that post (and its comments when asked); a photo of an album (`?single`) reads the album's post. Up to 100 channels and 200 post links a run.

Only **public channels** have the web preview this Actor reads. A name that is a **group**, a **person** or a **bot**, a **private invite link** (`t.me/+...`), a link to a private channel (`t.me/c/...`), and a channel whose owner turned its preview off get a free `notFound` row saying which (a channel with its preview off still gets its channel row, with the exact subscriber count). A renamed channel is followed to its new username.

#### History and dates

Each channel is read newest first, 20 posts a page, back through its history up to **Max posts per channel** (100 by default, up to 20,000) or to its first post. **Posted after** stops at the first older post, so `7 days` reads only the last week; **Posted before** reads past newer posts without returning them. Dates are in UTC.

#### Search terms, keywords and filters

**Search terms** use Telegram's own search of each channel: fast, and it matches word forms the way Telegram does, but Telegram returns only the newest 20 or so matches per channel and term. For older matches, or several words at once, use **Only posts containing**: the channel is read back page by page and each post's text, link preview and poll is checked (case and accents don't matter; a hashtag such as `#breaking` matches the post's hashtag). Reading stops after 500 posts in a row without a match. **Exclude words**, **Only posts with media** and **Minimum views** narrow either. Service posts (pins, a new name or photo, "Channel created") are left out unless you ask for them.

#### Comments

**Comments per post** (0 by default, up to 100) reads the newest comments of each post returned, from Telegram's comments widget, as rows after their post; the post row gets `commentsCount`. Only channels with a discussion group have comments: a post without one gets `commentsOff`, and after three such posts in a row the channel's comments aren't asked for again. A run reads the comments of up to 500 posts, shared between its channels. Each comment is a result, and Max results counts them.

### Monitoring channels on a schedule

1. Switch on **Only changes since the last run**. Optionally pick the **Changes to return**.
2. Run it once: the first run returns each channel's newest posts (up to Max posts per channel) as `firstRun` and saves them as the baseline.
3. Schedule it (Apify Console, Schedules). Each later run returns only the changes.

How it decides:

- Each run reads every post since the last run's newest one, and at least **Max posts per channel** (the window it watches for edits and deletions), comparing each with the history.
- A post newer than the last run's newest is `newPost`. An older post the history doesn't know (it was outside the last window) is recorded quietly, not reported.
- A post whose text, media or poll changed is `edited`, with its text before (up to 600 characters). Views and reactions don't count as edits.
- A post missing from the window is checked on its own page (up to 60 a run): "Post not found" reports it `deleted` at once; a post whose page still answers is left alone. Without a page check, it is reported after missing two runs in a row.
- Channel searches (Search terms) report new matches only: an edit can move a post out of a search, which isn't a deletion.
- Channel rows carry the subscriber count and its change since the last run.
- Histories are kept per channel, search term and filters (two monitors with different filters don't mix), in the key-value store `telegram-monitor-history`, or one you name in **History name**.
- Only what a run returns moves the history: if Max results or your spending limit stops a run, the changes it didn't return come with the next run.

### Alerts in Slack, Discord or Microsoft Teams

Paste an incoming-webhook URL in **Alert webhook URL** (Slack, Discord, Microsoft Teams, or any HTTPS endpoint that takes JSON, such as Zapier, Make or n8n). It switches on Only changes. The first run posts one short "alerts are set up" message; each later run posts its changes (new posts by default, or those you pick in **Alert on**: edited and deleted posts too), up to 50 per run, each with the channel, text, image, views and link. The URL is treated as a secret and masked in logs. If posting fails, the run still succeeds and its status says why.

### Run summary for pipelines

Each run saves a `RUN_SUMMARY` record in its key-value store: per channel or search, the posts and pages read, the newest and oldest post id read, whether it reached the channel's first post, and the subscriber count; plus the changes, what didn't load and why, the filters used, and the requests made.

### Telegram API: use it from code or from an AI assistant

Start a run and get the rows in one call (replace `<YOUR_TOKEN>`; a call that waits gives up after 5 minutes, so start bigger runs without waiting and read the dataset afterwards):

```bash
curl -X POST "https://api.apify.com/v2/acts/akhil_rajesh~telegram-channel-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer <YOUR_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"channels": ["durov", "telegram"], "maxPostsPerChannel": 50, "postedAfter": "30 days"}'
```

Or from Python with `apify-client`:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_TOKEN>")
run = client.actor("akhil_rajesh/telegram-channel-scraper").call(run_input={
    "channels": ["WatcherGuru", "cointelegraph"], "keywords": ["bitcoin", "etf"],
    "maxPostsPerChannel": 200, "postedAfter": "14 days", "commentsPerPost": 20,
})
for row in client.dataset(run.default_dataset_id).iterate_items():
    if row["type"] == "post":
        print(row["date"], row["views"], row["text"][:80])
```

#### For AI agents: MCP server and live API

The Actor also runs as a **live endpoint** (Apify Standby): an **MCP server** that agents call directly, and plain HTTP endpoints. Once a Standby run is up, a request is answered in seconds; the first request starts one. Authenticate with your Apify API token in the `Authorization: Bearer <token>` header.

**MCP server** (Streamable HTTP): `https://akhil-rajesh--telegram-channel-scraper.apify.actor/mcp`

```json
{"mcpServers": {"telegram": {"type": "http", "url": "https://akhil-rajesh--telegram-channel-scraper.apify.actor/mcp",
  "headers": {"Authorization": "Bearer <YOUR_APIFY_TOKEN>"}}}}
```

In Claude Code:

```bash
claude mcp add --transport http telegram https://akhil-rajesh--telegram-channel-scraper.apify.actor/mcp --header "Authorization: Bearer <YOUR_APIFY_TOKEN>"
```

A client that can't send headers can use `https://akhil-rajesh--telegram-channel-scraper.apify.actor/mcp?token=<YOUR_APIFY_TOKEN>`; keep that URL private, as it carries your token. Through **Apify's MCP server** (`https://mcp.apify.com`, for Claude, ChatGPT, Cursor and other clients), add the tools with `https://mcp.apify.com?tools=akhil_rajesh/telegram-channel-scraper` (they appear as `akhil_rajesh--telegram-channel-scraper--get_channel_posts` and so on), then ask in plain words, for example *"what did @durov post this month, and which post got the most views?"*. Add them that way rather than through Apify's generic `call-actor` tool, which returns the rows only as text. Apify's MCP server doesn't offer Actors with a live endpoint to agents that pay per call with x402 or Skyfire: connect with an Apify account or API token.

| Tool | What it returns |
|---|---|
| `get_channel_posts` | Posts of up to 5 channels, newest first, with dates, keywords, excluded words, media and minimum views as filters, and comments if asked |
| `search_channel_posts` | Telegram's own search of the channels for your terms (the newest matches) |
| `get_channel_info` | One row per channel: exact subscribers, description, verified mark, counters, posting pace and average views |
| `get_posts` | Posts by link (t.me/channel/123), with their comments if asked |
| `run_actor` | The Actor's whole input in one call |

**HTTP endpoints**, such as `GET https://akhil-rajesh--telegram-channel-scraper.apify.actor/posts?channels=durov|telegram&perChannel=20&after=7 days` (separate several channels, terms, words or links with `|`; defaults in brackets). The Actor's **Endpoints** tab in Apify Console lists them too, and lets you try them.

| Endpoint | Parameters |
|---|---|
| `GET /posts` | `channels`, `perChannel` (20), `max` (100), `after`, `before`, `keywords`, `exclude`, `media`, `minViews`, `service`, `channelInfo`, `comments` (0) |
| `GET /search` | `channels`, `terms`, `perChannel` (22), `max` (100), `channelInfo`, `comments` (0) |
| `GET /channel` | `channels` |
| `GET /post` | `posts` (links), `comments` (0) |
| `POST /run` | The Actor's whole input as the JSON body |

**Answers** carry the `rows`, `rowsByType`, `notFound` (names or posts Telegram can't show: free), `notLoaded` (what Telegram didn't answer), `notRead` (what a limit left out: not charged) and `notes`. A request that reads nothing gets an `error` and nothing is charged: HTTP 400 for an argument it can't read (a tool error over MCP), 503 when Telegram didn't answer or the run was busy (send it again), 402 when your spending limit for the run is reached (it lifts when the run ends, after 2 minutes without requests). A 503 can also carry rows, when the platform stopped the run while a request was being read: those were stored and charged, and `notRead` names the rest.

**Limits per request**: an MCP tool call reads up to 5 channels, 200 rows and 20 comments per post, about 350 kB of rows, within 50 seconds (MCP clients stop waiting at 60 seconds, and Apify's MCP server drops answers over about 1 MB); an HTTP request reads up to 20 channels, 2,000 rows and about 6 MB within 170 seconds. What a limit leaves out is named in `notRead` and isn't charged. **A request that has started runs to its end even if you stop waiting**: Apify's Standby proxy keeps it open, so its rows are read and charged. Ask for what you need. Monitoring (Only changes) and alerts belong to scheduled runs: the live endpoint answers each request on its own, so it ignores those fields.

### How much does it cost?

You pay **$1.00 per 1,000 results** (posts, comments and channel rows), less on paid Apify plans, plus a start fee of $0.00005 per run. **Platform usage is included** in runs of the Actor: there is no compute charge on top, and no row cap on Apify's free plan. (The Store page's pricing box mentions platform usage because of the live endpoint, which charges its own; ordinary runs never do.) Not-found rows are free. With Only changes you pay only for the changes returned (and one channel row per channel, unless you switch Channel details off). The live endpoint (MCP server and HTTP API) charges results at the same prices, plus the Standby run's platform usage while it serves you and until it has been idle for 2 minutes (a short session costs a fraction of a cent).

| Apify plan | Per 1,000 results |
|---|---|
| Free | $1.00 |
| Starter | $0.90 |
| Scale | $0.80 |
| Business and above | $0.70 |

| Run | Results | Cost (Free plan) |
|---|---|---|
| A channel's last 1,000 posts | 1,001 | about $1.00 |
| 20 channels, their last 50 posts each | 1,020 | about $1.02 |
| 100 posts with 20 comments each | 2,100 | about $2.10 |
| A monitor of 10 channels every hour, about 2 new posts a run each | about 720 a day | about $0.72 a day |

Apify's free plan ($5 of monthly credit) covers about 5,000 results. To cap spending, lower Max results or set a maximum cost per run in the run options; the Actor stops cleanly at the limit (and with Only changes, the rest comes with the next run).

### Good to know

- **Speed**: a page of 20 posts takes about a third of a second, so 1,000 posts read in about 20 seconds. Comments take one request per post.
- **What the preview shows**: views and reactions rounded past 999, an "edited" mark without the time of the edit, and no forward counts. Some posts (paid posts, stories, giveaways) aren't shown on the web at all: their row has `contentNotShown`. A video too big for the web has only its thumbnail (`mediaTooBig`).
- **Media links expire**: they carry Telegram's access token. Download what you need soon after the run.
- **Refusals**: a run that meets a refusal (Telegram's "Too Many Requests") waits and asks again, then names what it couldn't read and charges nothing for it.
- **Groups and private chats** need a Telegram account to read, which this Actor never uses.

### FAQ

**Do I need a Telegram account, API id or phone number?** No. The Actor reads the public web preview of channels, which needs no login.

**Can I get alerts for new posts in a Telegram channel?** Yes: switch on Only changes, paste a Slack, Discord or Teams webhook in Alert webhook URL, and schedule it (every 5 to 60 minutes). Each new post is posted once.

**Can it detect deleted or edited Telegram posts?** Yes, with Only changes: an edited post comes with its text before the edit, and a deleted post is confirmed on its own page ("Post not found") before it is reported.

**Can I scrape a channel's whole history?** Yes: set Max posts per channel high (up to 20,000) or Posted after to a date, and it reads back page by page to the channel's first post.

**Can I search Telegram for a keyword?** Within the channels you name, yes: Search terms (Telegram's own search, newest matches) or Only posts containing (the whole history, filtered). A search across all of Telegram needs a logged-in account, which this Actor doesn't use.

**Can it scrape Telegram groups or members?** No: groups and their members need a login. A group's name gets a free row saying so.

**Does it download photos and videos?** It returns their links (and thumbnails, durations and file names); the links work for a while, so download them soon after the run.

**Are view counts exact?** Telegram's preview rounds them past 999 ("34.6K"), and so does this Actor's `views`. Subscriber counts on channel rows are exact.

**Do I need a proxy?** No: Telegram answers Apify's servers directly. You can use your own proxies or Apify's datacenter proxies; residential proxies aren't available in this Actor, as they're billed per GB on top of the result price.

**Is it legal?** The Actor reads public channel pages that Telegram shows to anyone on the web, at a modest pace, without logging in. Use the data in line with Telegram's terms and the laws that apply to you, especially for personal data such as commenters' names.

### Other Actors by this developer

- [Google Ads Transparency API & Scraper](https://apify.com/akhil_rajesh/google-ads-transparency-scraper): every ad a brand runs on Google Search, YouTube, Shopping and Maps, with ad copy and targeting, political ad spend and ads Google removed, plus Slack, Discord or Teams alerts for new and stopped ads
- [Craigslist Scraper & Tracker](https://apify.com/akhil_rajesh/craigslist-scraper): Craigslist listings by keyword, city or state, with price drops, new and gone listings, and alerts
- [Kijiji Scraper & Tracker](https://apify.com/akhil_rajesh/kijiji-scraper): Kijiji listings by keyword, city and category with prices and price drops, cars and rentals, plus Slack, Discord or Teams alerts
- [Yahoo Finance Scraper & API](https://apify.com/akhil_rajesh/yahoo-finance-scraper): stock quotes, history, financials, options and news, with an MCP server
- [App Store Reviews Scraper & API](https://apify.com/akhil_rajesh/app-store-reviews-scraper): App Store reviews, ratings and rankings, with Slack, Discord or Teams alerts for new reviews

### Disclaimer

This Actor is an independent tool. It is not affiliated with, endorsed by or sponsored by Telegram. It reads publicly available channel pages at a modest pace and never logs in. Use the data in line with Telegram's terms and the laws that apply to you.

# Actor input Schema

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

Public Telegram channels: a username ('durov', '@telegram') or a link (t.me/durov, https://t.me/s/durov). A post link (t.me/durov/400) reads that post, with its comments if you ask for them. Groups, people, bots and private invite links can't be read without a login: they get a free 'notFound' row saying why.

## `searchTerms` (type: `array`):

Search each channel with Telegram's own search ('bitcoin', 'update', '#news'). Telegram returns the newest 20 or so matches per channel and term; for older matches use Only posts containing below, which reads the channel's history and filters it.

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

Posts read per channel (or per channel and search term), newest first, back through its history 20 at a time. With Only changes: the newest posts each run watches for edits and deletions.

## `maxResults` (type: `integer`):

Most rows a run returns (posts, comments and channel rows), shared between channels. With Only changes: most changes a run returns, with one channel row per channel on top (the rest of the changes come with the next run).

## `postedAfter` (type: `string`):

Only posts from this time on: a date ('2026-10-01', from 00:00 UTC), a date and time ('2026-10-01T08:00:00Z'), or an amount of time back from now ('7 days', '24 hours', '2 weeks'). Reading stops at the first older post.

## `postedBefore` (type: `string`):

Only posts up to this time (same forms as Posted after). Newer posts are read past, not returned.

## `includeChannelInfo` (type: `boolean`):

Add one row per channel: name, description, the exact subscriber count, verified mark, avatar, the preview's photo, video and link counts, and the posting pace and average views of its newest posts. With Only changes it also gives the change in subscribers since the last run.

## `commentsPerPost` (type: `integer`):

Read the newest comments of each post (up to 100; 0 for none), from Telegram's comments widget: commenter, text, time and what it replies to. Each comment is a row. Only channels with comments switched on have them.

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

Only posts whose text, link preview or poll has any of these words or phrases ('bitcoin', 'interest rate', '#breaking'). Case and accents don't matter. The channel is read back page by page and filtered (stopping after 500 posts in a row without a match).

## `excludeWords` (type: `array`):

Leave out posts with any of these words or phrases ('giveaway', 'sponsored', '#ad').

## `onlyWithMedia` (type: `boolean`):

Only posts with a photo, video, file, voice note, sticker or poll.

## `minViews` (type: `integer`):

Only posts with at least this many views. Leave empty or 0 for any.

## `includeServicePosts` (type: `boolean`):

Also return channel events such as pinned posts, a new name or photo, and 'Channel created'.

## `onlyChanges` (type: `boolean`):

Track your channels: each run returns only what changed since the last run with the same channels and filters: new posts, edited posts (with the text before), and deleted posts. The first run saves the newest posts as the baseline and returns them as firstRun. Schedule it (every hour, every day) to monitor channels.

## `changeTypes` (type: `array`):

Which changes Only changes returns. Leave empty for all.

## `alertWebhookUrl` (type: `string`):

Post each run's changes to Slack, Discord or Microsoft Teams (their incoming-webhook URL), or to any HTTPS endpoint that takes JSON (Zapier, Make, n8n). Switches on Only changes. The first run posts a short 'alerts are set up' message.

## `alertChangeTypes` (type: `array`):

Which changes are posted. Leave empty for new posts.

## `historyName` (type: `string`):

Keep a separate history for this monitor (a-z, 0-9 and hyphens). Leave empty to share the default one: histories are kept per channel and filters anyway.

## `proxy` (type: `object`):

Not needed: Telegram answers Apify's servers directly. You can use your own proxies or Apify's datacenter proxies; residential proxies aren't available in this Actor.

## Actor input object example

```json
{
  "channels": [
    "telegram",
    "durov"
  ],
  "maxPostsPerChannel": 20,
  "maxResults": 1000,
  "includeChannelInfo": true,
  "commentsPerPost": 0
}
```

# Actor output Schema

## `posts` (type: `string`):

No description

## `changes` (type: `string`):

No description

## `engagement` (type: `string`):

No description

## `media` (type: `string`):

No description

## `comments` (type: `string`):

No description

## `channels` (type: `string`):

No description

## `notFound` (type: `string`):

No description

## `allData` (type: `string`):

No description

## `runSummary` (type: `string`):

No description

# 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"
    ],
    "maxPostsPerChannel": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("akhil_rajesh/telegram-channel-scraper").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",
    ],
    "maxPostsPerChannel": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("akhil_rajesh/telegram-channel-scraper").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"
  ],
  "maxPostsPerChannel": 20
}' |
apify call akhil_rajesh/telegram-channel-scraper --silent --output-dataset

```

## MCP server setup

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

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/Xf4joDMp1kDdnztr8/builds/PPICVH6sklJbHdycD/openapi.json
