# Telegram Channel Scraper - Messages, Views & Reactions (`a.actors/telegram-channel-scraper`) Actor

Export any public Telegram channel: message text, timestamps, view counts, reactions broken out per emoji, forwarded-from attribution, media types, link previews and outbound links. No API key, no phone number, no account. Date range and per-channel caps included.

- **URL**: https://apify.com/a.actors/telegram-channel-scraper.md
- **Developed by:** [ApifyActors](https://apify.com/a.actors) (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 $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 and reactions, no API key

Export the full history of any public Telegram channel. No API key, no phone number, no
account, no Telethon session — point it at `@handle` and get rows.

### What you get

Text, timestamp, view count, **reactions broken out per emoji**, forwarded-from attribution
with its link, media types, link-preview metadata, outbound links, and a reply flag. Channel
title, description and subscriber count come attached to every row at no extra charge —
several actors in this category bill a separate "channel info" event for exactly that.

### Input

| Field | What it does |
|---|---|
| `channels` | `@handle`, bare handle, `t.me/handle` or `https://t.me/s/handle` |
| `maxMessagesPerChannel` | `0` for the whole history, or a cap to control spend |
| `onlyMessagesNewerThan` | ISO date. Paging stops as soon as the channel passes it |
| `onlyMessagesOlderThan` | ISO date upper bound, for a closed range |
| `useProxy` | Off by default — Telegram serves this without one |
| `delayBetweenPagesSecs` | Pacing for very long histories |

```json
{
  "channels": ["@durov", "telegram"],
  "maxMessagesPerChannel": 500,
  "onlyMessagesNewerThan": "2026-09-01"
}
```

### Output

One row per message:

```json
{
  "channel": "durov",
  "message_id": 528,
  "url": "https://t.me/durov/528",
  "datetime": "2026-09-18T14:22:07+00:00",
  "text": "Telegram now supports…",
  "views": "1.25M",
  "reactions": { "👍": "106", "❤": "3", "stars": "14.3K" },
  "reactions_total": 233765,
  "forwarded_from": null,
  "forwarded_from_link": null,
  "media": ["video"],
  "is_reply": false,
  "link_preview_site": "Telegram",
  "link_preview_title": "Welcome Messages, Buttons in Messages and Signed Gifts",
  "link_preview_desc": "Introducing Welcome Messages…",
  "link_preview_url": "https://telegram.org/blog/welcome-messages-buttons-TG-13",
  "links": ["https://telegram.org/blog/welcome-messages-buttons-TG-13"],
  "channel_title": "Durov's Channel",
  "channel_description": "Thoughts from the Telegram founder.",
  "subscribers": "9.48M",
  "scraped_date": "2026-09-24T09:02:11Z"
}
```

`reactions` keeps Telegram's own labels: the emoji itself where there is one, `stars` for
paid reactions, and `custom:<id>` for premium custom emoji. `reactions_total` is the sum,
already expanded from Telegram's shorthand — `14.3K` counts as 14,300.

### Pricing

**$0.50 per 1,000 messages**, plus Apify's standard $0.00005 actor start. Channel metadata
is free, date filtering is free, and channels that fail are not charged.

### Notes and limits

- **Public channels only.** Private channels, invite-only channels and groups have no public
  preview; they come back as an error row rather than an empty dataset, and cost nothing.
- **Two things this surface genuinely does not carry: comment counts and forward/share
  counts.** They exist only through an authenticated Telegram client, which is what actors
  that ask for your `api_id`/`api_hash` are doing. If you need those numbers, this is the
  wrong tool and the README of a Telethon-based actor is the right one.
- **An album counts as one message, not one per image.** That matches how Telegram itself
  numbers it and how analysts count posts.
- Very long histories are paged in blocks of roughly twenty messages, so a full 10,000-message
  archive is a few hundred requests. Use the date bound where you can.

### FAQ

**Do I need api\_id / api\_hash / a phone number?** No. That is the point.

**Can it read a group?** No — groups have no public preview surface.

**Can it search across all of Telegram by keyword?** No. It reads channels you name.

**Is the view count real?** It is the number Telegram publishes on the message, including its
shorthand for large values; `views` keeps the original string so nothing is invented.

# Actor input Schema

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

One entry per channel. Accepts @handle, a bare handle, t.me/handle or https://t.me/s/handle. Public channels only - private channels and groups are reported as an error row and are not charged.

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

0 = every message back to the date bound, or to the start of the channel if no bound is set. Set a number to cap both runtime and spend.

## `onlyMessagesNewerThan` (type: `string`):

ISO date, e.g. 2026-01-01. Paging stops as soon as the channel goes past it. No extra charge for filtering.

## `onlyMessagesOlderThan` (type: `string`):

ISO date upper bound, for pulling a closed range.

## `useProxy` (type: `boolean`):

Off by default, because Telegram serves this surface without one. Turn it on only if a very large job starts hitting rate limits.

## `delayBetweenPagesSecs` (type: `integer`):

Seconds between page requests within one channel. Raising it trades speed for a lower chance of being throttled on long histories.

## Actor input object example

```json
{
  "channels": [
    "@durov"
  ],
  "maxMessagesPerChannel": 100,
  "onlyMessagesNewerThan": "",
  "onlyMessagesOlderThan": "",
  "useProxy": false,
  "delayBetweenPagesSecs": 1
}
```

# Actor output Schema

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

One item per message: text, timestamp, views, reactions per emoji, forwarded-from, media types, link preview and outbound links, with channel title and subscriber count attached. Channels that failed appear as error rows and are not charged.

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

Counts of channels read, messages collected and channels that failed.

# 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"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("a.actors/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": ["@durov"] }

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

```

## MCP server setup

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