# Telegram Channel Scraper: Posts, Views, Analytics | $0.25 / 1K (`hridayrungta/telegram-channel-scraper`) Actor

Telegram channel data without an API key or login: messages, views, reactions, forwards, subscribers and media links from public channels. Keyword filter, date range and incremental monitoring. From $0.25 per 1,000 messages.

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

## Pricing

from $0.25 / 1,000 message scrapeds

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: public channel posts, views and analytics (no API key)

**Get Telegram channel data without a Telegram account, API ID or bot token.** Give it channel usernames or t.me links and get structured messages: text, date, views, reactions, forwards, replies, links, hashtags, media URLs and channel info (title, description, subscribers). Built for Telegram channel monitoring, crypto and news tracking, channel analytics, OSINT and market research.

**$0.25 per 1,000 messages** plus a $0.002 start fee per run. It reads the public web preview Telegram serves at `t.me/s/<channel>`: no login, no browser, no proxy.

### What can you use Telegram channel data for?

- **Telegram channel analytics**: subscribers, views, reactions and forwards per post, to compare channels or track growth over time.
- **Crypto, news and market monitoring**: schedule it and receive only new posts, with a keyword filter.
- **Channel archive and export**: save a channel's history to CSV, Excel or JSON, by date range.
- **OSINT and research**: collect public messages, links, hashtags and media URLs.
- **Lead and competitor research**: see what public channels in your niche post and what gets engagement.

### Telegram API alternative: what is different

Telegram's official routes (Bot API, or the user API with your own API ID and login) need a bot token or an account, and a bot only sees channels it has been added to. This Actor needs neither, but it is also narrower: it only sees what a visitor sees on a public channel's web preview. No private channels, no groups, no member lists, no comments.

### What data you get

For every message (one dataset row, `type: "message"`):

- **Message**: channel, message ID, direct link, date (ISO, UTC), plain text and the original HTML (bold, links, formatting kept)
- **Reach**: views, every reaction with its count (including paid Star reactions), total reactions
- **Context**: forwarded-from channel, reply-to message (ID, author, quoted text), post author signature, edited flag
- **Media**: media type (`photo`, `video`, `document`, `voice`, `sticker`, `poll`, `mixed`), media list with image/video URLs, thumbnails, duration, document title and size, poll question and results
- **Link preview**: URL, site name, title, description, image
- **Extracted**: external links, @mentions, #hashtags

Plus one **channel info row** per channel (`type: "channel"`, free): title, username, description, subscribers, verified flag, photo, number of photos/videos/links, and a `status`.

#### Example output

```json
{
  "type": "message",
  "channel": "durov",
  "messageId": 531,
  "url": "https://t.me/durov/531",
  "date": "2026-07-16T20:45:25.000Z",
  "text": "Telegram now has a Rich Text Editor. ...",
  "views": 5800000,
  "reactions": [
    { "emoji": "⭐", "customEmojiId": null, "paid": true, "count": 6300 },
    { "emoji": null, "customEmojiId": "5265077361648368841", "paid": false, "count": 54600 }
  ],
  "reactionsTotal": 94990,
  "postAuthor": "Pavel Durov",
  "forwardedFrom": null,
  "replyTo": null,
  "edited": false,
  "mediaType": "video",
  "mediaCount": 1,
  "media": [{ "type": "video", "url": "https://cdn4.telesco.pe/file/...mp4", "thumbnail": "https://cdn4.telesco.pe/file/...jpg", "duration": "0:06" }],
  "linkPreview": null,
  "links": [],
  "mentions": [],
  "hashtags": [],
  "scrapedAt": "2026-10-14T04:52:50.000Z"
}
```

### How to scrape a Telegram channel

1. Open the Actor and add channels under **Channels**: `durov`, `@durov` or `https://t.me/durov`.
2. Set **Max messages per channel** (newest first).
3. Optional: a date range (**newer than / older than**), a **keyword filter**, or **Only new messages since last run**.
4. Click **Start**, then download the dataset as JSON, CSV, Excel or via the API.

Example input, the last week of a channel filtered by keyword:

```json
{
  "channels": ["cointelegraph"],
  "keywords": ["bitcoin", "etf"],
  "newerThan": "7 days",
  "maxMessagesPerChannel": 200
}
```

### Input

| Field | What it does |
|---|---|
| `channels` | Required. Usernames or t.me links, one per line. Private invite links (`t.me/+...`) cannot be read. |
| `maxMessagesPerChannel` | Cost cap per channel. Default 100. |
| `newerThan` / `olderThan` | Date range. `YYYY-MM-DD` or a span like `"7 days"`, `"12 hours"`. Old ranges of big channels are reached directly, without paging through everything newer. |
| `keywords` | Only save messages containing at least one keyword (not case sensitive). Non-matching messages are not billed. |
| `incremental` | Each run after the first returns only messages newer than the last run, per channel. |
| `firstRunSince` | How far back a channel's first incremental run looks. Default `"7 days"`, or `"all"` for a full backfill. |
| `includeChannelInfo` | Add the free channel info row. Default on. |
| `maxTotalMessages` | Hard cap across all channels. Default 10,000. |

### Pricing (pay per event)

No subscription.

| Event | Price |
|---|---|
| Actor start (once per run) | $0.002 |
| Message scraped | $0.00025 ($0.25 per 1,000 messages) |

Channel info rows, status rows and messages removed by your keyword filter are never charged.

Worked examples:

- Latest 20 messages of one channel: $0.002 + 20 x $0.00025 = **$0.007**.
- 1,000 messages: $0.002 + $0.25 = **$0.252**.
- Checking 50 channels every hour for new posts: you pay the start fee per run plus only the messages that are actually new.

### Monitor channels over time (incremental mode)

Turn on `incremental` and schedule the Actor (for example hourly). It remembers the newest message seen per channel in a named key-value store and only returns newer messages next time, so you never pay twice for the same message. Use `stateNamespace` to keep several independent monitors apart.

### Schedule it and connect it

Use an [Apify Schedule](https://docs.apify.com/platform/schedules) for recurring runs, then send new messages to **Google Sheets**, **Make**, **n8n**, **Zapier**, Slack via a **webhook**, or your own database. The Apify API and MCP server let scripts and AI agents call it too.

### Channels that cannot be read

Telegram only publishes a web preview for **public channels whose owner has not switched it off**. For anything else the Actor does not fail and does not charge. It returns one `type: "channel"` row with a status:

| Status | Meaning |
|---|---|
| `ok` | Messages were read. |
| `preview_disabled` | The channel or group exists but has no public web preview (all groups, and channels that opted out). Needs a Telegram account, so it cannot be scraped here. |
| `not_found` | No public channel, group or user with that username. |
| `not_a_channel` | The username belongs to a user or bot. |
| `no_messages` | The preview is on but shows no messages. |
| `fetch_failed` | Telegram could not be reached after retries. |

### Known limits

- Public channels only. No private channels, no groups, no member lists, no comments, no replies from other users.
- The preview shows what a visitor sees. Custom emoji reactions come as IDs (`customEmojiId`), not characters.
- Media files are returned as URLs, not downloaded. Large videos are missing from the preview; those rows have a thumbnail and a message URL but no video `url`.
- Album posts appear as one message with several media items. Service messages (pins, joins) are skipped.
- Views, reactions and subscriber numbers are as of scraping time and rounded by Telegram above 1,000 (for example "1.2K").
- Media links carry a time-limited token. Download files soon after scraping.
- Search across all of Telegram is not possible with the public preview; `keywords` filters inside the channels you list.

### FAQ

**Do I need a Telegram account or API key?** No.

**Is this a Telegram bot or API client?** No. It reads the public web preview, so it only sees what any visitor sees without logging in.

**Can I get Telegram channel analytics like subscribers and views?** Yes: subscribers come from the channel info row, views, reactions and forwards from each message. It does not show private admin statistics.

**How far back can I go?** As far as the web preview goes. In testing it reached back several years on a large news channel (use the date range to jump there).

**How fast is it?** About 20 messages per request. A 1,000-message run on a large news channel took under 2 minutes in testing.

**Can I use it with ChatGPT or Claude?** Yes, via the Apify API or MCP server.

**Is it legal?** It collects only public data that Telegram shows to anyone. You are responsible for respecting Telegram's Terms of Service, privacy and data-protection laws (such as GDPR) and channel owners' rights.

### Related Actors

- [Reddit Scraper](https://apify.com/hridayrungta/reddit-scraper) (own): posts and comments for community monitoring.
- [Bluesky Scraper](https://apify.com/hridayrungta/bluesky-scraper) (own): posts, threads and followers.
- [YouTube Scraper](https://apify.com/hridayrungta/youtube-scraper) (own): videos and channels.
- [Telegram Scraper by tri_angle](https://apify.com/tri_angle/telegram-scraper) (third party): another Telegram Actor.
- [Telegram Messages Scraper by curious_coder](https://apify.com/curious_coder/telegram-scraper) (third party): another Telegram Actor.

# Actor input Schema

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

Public channels to scrape, one per line: a username ("durov"), an @username, or a link such as https://t.me/durov or https://t.me/s/durov. Private invite links (t.me/+...) cannot be read.

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

Cost cap per channel. You are billed once per message saved. The newest messages come first.

## `newerThan` (type: `string`):

Optional. A date (YYYY-MM-DD) or a span such as "7 days" or "12 hours". Messages older than this are skipped and paging stops there.

## `olderThan` (type: `string`):

Optional. A date (YYYY-MM-DD) or a span such as "30 days". Combine with "newer than" to get a date range. The Actor jumps straight to that part of the history, so old ranges of big channels stay cheap.

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

Optional. Only save messages whose text contains at least one of these words or phrases (not case sensitive). Messages that do not match are not billed.

## `incremental` (type: `boolean`):

When on, each run after the first returns only messages newer than the last run, per channel. Ideal for scheduled monitoring.

## `firstRunSince` (type: `string`):

A channel's first incremental run only takes messages since this date/span, never its whole history. Default "7 days"; use "all" for a deliberate full backfill.

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

Adds one extra row per channel (title, description, subscribers, photo, status). Never billed.

## `maxTotalMessages` (type: `integer`):

Hard cap across all channels.

## `maxRetries` (type: `integer`):

Retries with backoff for network errors, rate limits and 5xx responses.

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

Named key-value store that keeps the high-water marks between runs.

## `stateNamespace` (type: `string`):

Optional label to keep several independent monitors apart. Leave empty to use one shared set of marks per account.

## Actor input object example

```json
{
  "channels": [
    "durov"
  ],
  "maxMessagesPerChannel": 20,
  "keywords": [],
  "incremental": false,
  "firstRunSince": "7 days",
  "includeChannelInfo": true,
  "maxTotalMessages": 10000,
  "maxRetries": 3,
  "stateStoreName": "telegram-channel-scraper-state"
}
```

# Actor output Schema

## `results` (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": [
        "durov"
    ],
    "maxMessagesPerChannel": 20,
    "keywords": []
};

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

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

```

## MCP server setup

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