# Telegram Channel Scraper — Subscribers, Views, Reach Rate (`northwestsouth/telegram-channel-analytics`) Actor

Public Telegram channel metrics other scrapers skip: subscriber count, median views, reach rate, posting cadence — plus the posts. No API key, no login. Pay per channel; unreadable channels are free.

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

## Pricing

$10.00 / 1,000 channel analyseds

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/platform/actors/running/actors-in-store#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 Scraper — subscribers, views, reach rate

Every other Telegram actor in this store dumps messages. That leaves the more useful question unanswered: **is this channel worth anything?**

The same public page that carries the posts also carries the subscriber count and a view count on every post. Divide one by the other and you have reach — the number an advertiser, a researcher or a market watcher actually decides on. Nobody else returns it.

```json
{ "channels": ["durov", "whale_alert", "https://t.me/telegram"] }
```

```
durov         11,300,000 subscribers · median 1.2M views · reach 10.6% · 0.31 posts/day
whale_alert       13,600 subscribers · median  44.9K views · reach 330% · 4.2 posts/day
```

No API key. No login. No phone number. No session string.

### What you get per channel

| Field | Meaning |
|---|---|
| `subscribers` | From Telegram's own header |
| `median_views`, `mean_views` | Across the posts read |
| `reach_rate_percent` | Median views ÷ subscribers — **the differentiator** |
| `views_exceed_subscribers` | `true` when reach is above 100% (see below) |
| `posts_per_day` | Publishing cadence, from the timestamps |
| `forward_share_percent` | How much is original versus forwarded |
| `media_share_percent`, `link_share_percent` | What the channel actually publishes |
| `counts` | Photos, videos, links, files |
| `title`, `description`, `image` | Channel identity |
| `posts[]` | Post id, URL, timestamp, views, text, links, hashtags, media type, forward source |

### Reach above 100% is real, not a bug

`whale_alert` measures 330%. That is correct: Telegram counts **every** view, including people who saw the post forwarded into another channel, and an older post keeps accruing views while a channel's subscriber count can fall. Whenever this happens the row is flagged `views_exceed_subscribers: true` so you never have to wonder whether the parser broke.

### Telegram rounds its own numbers

The page says `13.6K`, not `13,647`. Every count is therefore rounded **at the source**, and `reach_rate_percent` inherits that rounding. Each row carries `counts_are_rounded` and each post carries `views_rounded`, so you can see exactly which figures are approximate. No other actor tells you this, and quietly presenting `13,600` as exact would be a small lie repeated on every row.

### Fair billing

- **You pay per channel analysed.** One row per channel; the posts ride inside it. Monitoring fifty channels costs fifty, not one per message.
- **A channel that cannot be read is free.** Private, deleted, group-only or misspelled — it goes to `TG-CHANNELS-NOT-FOUND` with the reason and costs nothing.
- **`onlyNewPosts` charges you once per post, ever.** Posts returned by an earlier run are skipped. A daily schedule then reports only what is genuinely new. Metrics are still computed over the whole page, so a monitoring run does not report reach based on a single new post.

### Why this data is fair to use

`t.me/s/<channel>` is the preview **Telegram itself publishes** so a public channel can be read without the app and without an account. That is its purpose. There is no login, no API key and no session; `t.me` serves no `robots.txt` at all, so no path is disallowed. One request per channel by default, paced.

Only **public** channels have such a page. Private channels, groups and direct messages have none and are reported as unreadable rather than reached by some other route. Subscriber lists and comment authors are not exposed by this page and are not collected.

### Useful setups

**Rank a list of channels before buying advertising**

```json
{ "channels": ["durov", "telegram", "whale_alert"], "includePosts": false }
```

Metrics only — small output, one request per channel.

**Daily monitoring, paying only for new posts**

```json
{ "channels": ["whale_alert", "cointelegraph"], "onlyNewPosts": true }
```

**Go back through the history**

```json
{ "channels": ["telegram"], "maxPostsPerChannel": 200 }
```

Telegram serves 20 posts per page, so this costs one extra request per 20 posts. Capped at 500.

### Limits worth knowing

- **20 posts per request.** Deeper history costs proportionally more requests and time.
- **View counts are per post, not per day.** Telegram publishes a running total, so an old post looks stronger than a new one. Compare posts of similar age.
- **Metrics describe the window that was read**, not the channel's whole life. With the default 20 posts, `posts_per_day` reflects recent cadence.
- **Some channels hide view counts.** Then `median_views` and `reach_rate_percent` are `null` rather than guessed.

### Support

A channel that should work but doesn't, or a field parsed wrongly? [Open an issue](https://console.apify.com/actors) — both count as bugs and get fixed.

# Actor input Schema

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

Channel names, @handles or links: "durov", "@whale\_alert", "https://t.me/telegram". Only public channels have a preview page; private ones and groups cannot be read and cost nothing.

## `includePosts` (type: `boolean`):

ON by default. Turn off for a pure metrics sweep — much smaller output when you are only ranking channels.

## `includeMessageText` (type: `boolean`):

ON by default. Turning it off keeps timestamps, views, media type and link counts but drops the text.

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

Telegram serves 20 posts per page. Asking for more pages back through the history costs one extra request per 20 posts. Capped at 500.

## `onlyNewPosts` (type: `boolean`):

For monitoring. Posts already returned by an earlier run are skipped, so a daily schedule reports only what is genuinely new. Channel metrics are still calculated over the full page.

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

ISO date, e.g. 2026-08-01. Leave empty for everything on the page.

## Actor input object example

```json
{
  "channels": [
    "durov",
    "telegram",
    "whale_alert"
  ],
  "includePosts": true,
  "includeMessageText": true,
  "maxPostsPerChannel": 20,
  "onlyNewPosts": false
}
```

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

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

# Run the Actor and wait for it to finish
run = client.actor("northwestsouth/telegram-channel-analytics").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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",
    "telegram",
    "whale_alert"
  ]
}' |
apify call northwestsouth/telegram-channel-analytics --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=northwestsouth/telegram-channel-analytics",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/VkgbsakAhwNrSQiea/builds/P7NXIcY4d1TpAgUGK/openapi.json
