# Telegram Channel Scraper: Messages, Views & Reactions (`magenta_waterwheel/telegram-channel-scraper`) Actor

Scrape public Telegram channels without login or API keys: message text, date, views, reactions, photos, videos, links, hashtags, replies and forwards, plus channel title, description and subscriber count. Date range, keyword filter and new-messages-only monitoring. $0.50 per 1,000 messages.

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

## Pricing

from $0.50 / 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.

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: Messages, Views & Reactions

**Telegram Channel Scraper** extracts **messages from public Telegram channels** without a Telegram account, phone number, bot token or API keys. Get message text, date, **view counts**, **reactions** (including paid star reactions), **photos, videos and documents**, links, hashtags, mentions, **replies and forwards**, link previews, polls and inline buttons, plus a **channel info** record with title, description and **full subscriber count**.

It reads Telegram's public web preview (`t.me/s/<channel>`), so runs are fast and cheap: no browser, no login, no proxies needed. Filter by **date range** and **keywords**, or monitor channels on a schedule and get **only new messages since the last run**. Export to JSON, CSV or Excel, or connect via API, Make, Zapier or n8n.

### Why use this Telegram scraper?

|                                         | Telegram Channel Scraper                    | Telegram API (Telethon, MTProto) | Copying by hand |
| --------------------------------------- | ------------------------------------------- | -------------------------------- | --------------- |
| Account, phone number or API ID needed  | **No**                                      | Yes, and risk of account bans    | No              |
| Views, reactions, media links, forwards | Yes                                         | Yes                              | Partly          |
| Date range and keyword filters          | Yes, filtered-out messages are free         | You write the code               | Manual          |
| New-messages-only monitoring            | Yes, built in                               | You write the code               | No              |
| Full subscriber count (not just 10.5M)  | Yes                                         | Yes                              | Yes             |
| Price                                   | **$0.50 per 1,000 messages**, pay as you go | Free, but your time and servers  | Your time       |

### What can this Telegram channel scraper do?

- 💬 **Scrape Telegram channel messages**: text with line breaks, date, message ID and link, author signature, edited flag.
- 📈 **Engagement data**: view count and every reaction with its count, including paid ⭐ star reactions.
- 🖼️ **Media links**: photos, videos (with thumbnail and duration), GIFs, voice notes, audio, documents, stickers and locations. Albums are kept together as one message.
- 🔗 **Links, hashtags and @mentions** extracted from the text, plus the **link preview** card (site, title, description, image).
- ↩️ **Replies and forwards**: replied-to message ID and snippet, and the original channel and message of forwarded posts.
- 📊 **Polls and inline buttons**.
- 📇 **Channel info**: title, description, full subscriber count (10,468,000 rather than 10.5M), verified badge, avatar, and photo, video, link and file counters.
- 📅 **Date range filter**: only messages between two dates, or a relative period such as "last 7 days".
- 🔎 **Keyword filter**: only messages containing any (or all) of your keywords.
- 🔁 **Monitoring mode**: on a schedule, save only messages posted since the last run.

### Who uses Telegram channel data?

- **Crypto and trading analysts** tracking signal channels, project announcements and sentiment.
- **Journalists, OSINT and research teams** archiving public news and conflict channels.
- **Brand and PR teams** monitoring mentions of their company, products or competitors.
- **Marketers** benchmarking channel growth, views and engagement before buying ads.
- **AI and data teams** building datasets for LLM summarization, translation, topic clustering or sentiment analysis.

### How to scrape a Telegram channel

1. Click **Try for free**.
2. Add channels to **Channels**, one per line: a username (`durov`), an @handle (`@durov`) or a link (`https://t.me/durov`).
3. Set **Max messages per channel** and, optionally, a date range or keywords.
4. Click **Start**, then download the results from the **Output** tab.

### Input example

```json
{
    "channels": ["telegram", "@durov", "https://t.me/bloomberg"],
    "maxMessagesPerChannel": 200,
    "oldestDate": "30 days",
    "keywords": ["update", "launch"],
    "keywordMatch": "any",
    "includeChannelInfo": true
}
```

### Output examples

Every record has a `recordType` of `message` or `channel`. The **Messages** and **Channels** views in the Output tab show them separately.

**Message** (shortened)

```json
{
    "recordType": "message",
    "channel": "cointelegraph",
    "channelTitle": "Cointelegraph",
    "messageId": 72544,
    "url": "https://t.me/cointelegraph/72544",
    "date": "2026-10-08T05:11:39.000Z",
    "isEdited": true,
    "authorSignature": null,
    "text": "Today's the day for LONGITUDE Singapore 🇸🇬\n\nCatch these speakers on stage: ...",
    "views": 5690,
    "viewsText": "5.69K",
    "reactions": [
        { "emoji": "⭐", "customEmojiId": null, "isPaid": true, "count": 4 },
        { "emoji": "❤", "customEmojiId": null, "isPaid": false, "count": 19 },
        { "emoji": "🔥", "customEmojiId": null, "isPaid": false, "count": 10 }
    ],
    "reactionsTotal": 37,
    "media": [
        {
            "type": "photo",
            "url": "https://cdn5.telesco.pe/file/iNE2_DHJ...jpg",
            "thumbnailUrl": null,
            "postUrl": "https://t.me/cointelegraph/72544",
            "duration": null,
            "title": null,
            "description": null
        }
    ],
    "mediaCount": 1,
    "links": ["http://luma.com/2g8kwtyd", "https://cointelegraph.com/"],
    "hashtags": [],
    "mentions": [],
    "linkPreview": null,
    "replyTo": null,
    "forwardedFrom": null,
    "poll": null,
    "buttons": [],
    "isServiceMessage": false,
    "scrapedAt": "2026-10-08T16:50:01.112Z"
}
```

A forwarded message has `"forwardedFrom": { "name": "Telegram Premium", "url": "https://t.me/premium/144", "channel": "premium", "messageId": 144 }`, and a reply has `"replyTo": { "messageId": 4405, "url": "https://t.me/tginfo/4405", "author": "Telegram Info", "text": "..." }`.

**Channel**

```json
{
    "recordType": "channel",
    "channel": "durov",
    "url": "https://t.me/durov",
    "title": "Pavel Durov",
    "description": "Founder of Telegram.",
    "subscribers": 10468000,
    "subscribersText": "10.5M",
    "isVerified": true,
    "avatarUrl": "https://cdn4.telesco.pe/file/...jpg",
    "counters": { "photos": 102, "videos": 46, "links": 200 },
    "latestMessageId": 548,
    "scrapedAt": "2026-10-08T16:49:58.311Z"
}
```

A `RUN_SUMMARY` record in the key-value store shows messages saved and scanned per channel, why each channel stopped, and any channel that was not found or has no public preview.

### How much does it cost to scrape Telegram?

This Actor uses **pay-per-event** pricing. You only pay for the records you get:

| Event                     | Price                                              |
| ------------------------- | -------------------------------------------------- |
| Message saved             | **$0.50 per 1,000 messages** ($0.0005 per message) |
| Channel info record saved | **$1.00 per 1,000 channels** ($0.001 per channel)  |
| Actor start               | $0.00005 per run                                   |

Messages skipped by your date or keyword filters are free, and there's no extra charge for compute or proxies. Set **Maximum cost per run** in the run options to cap spending.

Examples:

- The prefilled example (2 channels, 50 messages each): about **$0.05**
- 10,000 messages: **$5.00**
- Channel info (subscribers, description) for 1,000 channels: **$1.00**
- Daily monitoring of 20 channels posting ~10 messages a day: about **$3 per month**

### Monitor Telegram channels for new messages

1. Turn on **Only new messages since the last run**.
2. Save the input as a **task** and add a **schedule** (for example every hour) in Apify Console.
3. Each run saves only messages newer than the newest one seen before, per channel. Runs with nothing new cost almost nothing.
4. Connect Slack, Google Sheets, a webhook or Make/Zapier/n8n to receive new messages automatically.

Use a different **Monitoring state store name** for each task so their positions don't mix. Combine with **Keywords** to get alerts only for messages that mention your brand, ticker or topic.

### Use it with AI agents (MCP) and the API

Add this Actor as a tool in Claude, ChatGPT, Cursor, VS Code or any other MCP client through the [Apify MCP server](https://docs.apify.com/mcp):

```text
https://mcp.apify.com?tools=magenta_waterwheel/telegram-channel-scraper
```

Then just ask, for example: *"Get the last 100 messages from @durov and @telegram and summarize what was announced this month."* The Actor runs with **limited permissions**, so it can only access its own run storage.

To get results in a single HTTP request, call the synchronous endpoint with your [Apify API token](https://console.apify.com/settings/integrations):

```bash
curl -X POST "https://api.apify.com/v2/acts/magenta_waterwheel~telegram-channel-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"channels":["durov"],"maxMessagesPerChannel":50,"includeChannelInfo":false}'
```

You can also use the official [Python](https://docs.apify.com/api/client/python) and [JavaScript](https://docs.apify.com/api/client/js) clients, or the ready-made code on the **API** tab.

### Integrations and scheduling

- ⏰ **Schedule runs** hourly, daily or weekly in Apify Console, with no server to maintain.
- 🔗 **Send results anywhere**: Google Sheets, Slack, Google Drive, Airbyte, webhooks, or no-code tools such as **Make, Zapier and n8n**.
- 📤 **Export** the dataset as JSON, CSV, Excel, XML, RSS or HTML.
- 📈 **Monitoring**: get notified if a run fails, and see every run's log and cost in Console.

### FAQ

#### Do I need a Telegram account, phone number or API key?

No. The Actor reads the public web preview that Telegram shows for every public channel at `t.me/s/<channel>`. Nothing is logged in, and your own Telegram account is never at risk.

#### Is there a free trial?

Yes. Apify's Free plan includes **$5 of usage credit every month**, enough for about **10,000 messages** with this Actor. No credit card is needed to start.

#### Which channels can I scrape?

Any **public channel** with a web preview, which is almost all public channels. Private channels, invite links (`t.me/+...`), groups and bots can't be read without logging in. The Actor lists them in `RUN_SUMMARY` as not found or without a public preview, and the rest of the run continues.

#### How far back can I go?

As far back as the channel's history goes. The Actor pages backwards about 20 messages at a time. For keyword or date searches, **Max pages without matches per channel** (default 50 pages, about 1,000 skipped messages) is a safety limit you can raise.

#### Can I get forward counts or comments?

Telegram's public web preview shows views and reactions, but not forward counts or the comments thread, so those fields aren't available without logging in.

#### Are view counts exact?

Telegram shows large view counts rounded (for example `1.74M`). `views` is the number as shown and `viewsText` is the original text. The channel record's `subscribers` comes from the channel page, which shows the full number (for example 10,468,000 instead of 10.5M).

#### Does it download the media files?

It returns direct links to photos, video files and thumbnails as Telegram serves them. Telegram's media links can expire after a while, so download files you need soon after the run. Very large videos only have a link to the post.

#### Is it legal to scrape Telegram?

The Actor only reads publicly available channel posts that anyone can see in a browser without logging in. Messages can contain personal data and copyrighted media, so make sure your use complies with applicable laws, such as GDPR, and with Telegram's terms.

#### I found a bug or need a feature

Open an issue in the **Issues** tab with a link to your run. We aim to reply within one business day.

If this saved you time, a quick rating on the Store helps a lot: [leave a review](https://apify.com/magenta_waterwheel/telegram-channel-scraper/reviews).

### More tools from the same developer

| Actor                                                                                       | What it does                                                                       | Price                     |
| ------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ------------------------- |
| [Career Site Jobs API](https://apify.com/magenta_waterwheel/career-site-jobs-api)           | Jobs from Greenhouse, Lever, Ashby and SmartRecruiters career sites, with salaries | $2 / 1,000 jobs           |
| [App Store Reviews Scraper](https://apify.com/magenta_waterwheel/app-store-reviews-details) | Apple App Store reviews and app details in any country                             | $0.25 / 1,000 reviews     |
| [Website Screenshot & PDF API](https://apify.com/magenta_waterwheel/website-screenshot-pdf) | Full-page PNG/JPEG screenshots and web page to PDF in bulk                         | $2.50 / 1,000 screenshots |
| [Document & PDF to Markdown](https://apify.com/magenta_waterwheel/document-to-markdown)     | PDF, Word, PowerPoint, Excel and HTML to LLM-ready Markdown, with OCR              | $3 / 1,000 pages          |

# Actor input Schema

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

Public Telegram channels, one per line: username (durov), @handle (@durov) or link (https://t.me/durov or https://t.me/s/durov). Private groups and invite links (t.me/+...) are not supported.

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

Maximum number of messages to save from each channel, newest first. Set 0 to save only channel info.

## `oldestDate` (type: `string`):

Only messages posted on or after this date. Use a date (2026-01-31), a date and time (2026-01-31T08:00:00Z) or a relative period such as "7 days" or "12 hours". Scraping stops when it reaches older messages.

## `newestDate` (type: `string`):

Only messages posted on or before this date (same formats as above). Newer messages are skipped for free.

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

Only save messages whose text (or link preview or poll question) contains these words or phrases. Case-insensitive. Messages that don't match are free.

## `keywordMatch` (type: `string`):

Save messages that contain any of the keywords, or only those that contain all of them.

## `maxPagesPerChannel` (type: `integer`):

Safety limit for date and keyword searches: stop a channel after this many pages (about 20 messages each) that contain no message you asked for. Pages with matches don't count. 50 pages is about 1,000 skipped messages.

## `onlyNewMessages` (type: `boolean`):

For scheduled monitoring. Remembers the newest message ID per channel in a named key-value store and on the next run saves only newer messages. The first run saves up to the message limit.

## `stateStoreName` (type: `string`):

Name of the key-value store that remembers the last message ID per channel. Use a different name for each monitoring task.

## `minMessageId` (type: `integer`):

Only save messages with an ID greater than this number (the number at the end of a message link, e.g. 460 in t.me/telegram/460). Useful for your own incremental logic.

## `includeMessages` (type: `boolean`):

Save channel messages.

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

Save one record per channel with title, description, full subscriber count, verification badge, avatar and media counters.

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

Also save the original message HTML (formatting, bold, links) in textHtml.

## `maxConcurrency` (type: `integer`):

How many pages to load in parallel. Pages of one channel are always loaded in order.

## `proxyConfiguration` (type: `object`):

Not needed in most cases. Use Apify Proxy if Telegram starts rate-limiting very large runs.

## Actor input object example

```json
{
  "channels": [
    "telegram",
    "@durov",
    "https://t.me/bloomberg"
  ],
  "maxMessagesPerChannel": 50,
  "keywordMatch": "any",
  "maxPagesPerChannel": 50,
  "onlyNewMessages": false,
  "stateStoreName": "telegram-channel-scraper-state",
  "includeMessages": true,
  "includeChannelInfo": true,
  "includeHtml": false,
  "maxConcurrency": 5
}
```

# Actor output Schema

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

No description

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

No description

## `allRecords` (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"
    ],
    "maxMessagesPerChannel": 50
};

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

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

```

## MCP server setup

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