# Telegram Channel Info Scraper — Subscribers & Stats (`thenetaji/telegram-channel-info-scraper`) Actor

Size up public Telegram channels before reading any of them: one row per channel with its title, handle, bio, subscriber count, the counters its header states, and its newest post number. No posts saved and no login; channel names come from the input list.

- **URL**: https://apify.com/thenetaji/telegram-channel-info-scraper.md
- **Developed by:** [The Netaji](https://apify.com/thenetaji) (community)
- **Categories:** Social media, Marketing, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.13 / 1,000 channels

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

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 Info Scraper

Find out how big a public Telegram channel is, and what it says about itself, without reading a
single post. Each channel in the list becomes one row: its display title, its handle, its bio, its
subscriber count, every counter its header states, and the number of its newest post. Hundreds of
channels can be looked up in one run.

Nothing is signed into. No bot token, no phone number and no API credentials are involved at any
point, because the source is the public channel preview that any browser can open at
`t.me/s/<channel>`. The channel names come from the run's input; Telegram publishes no directory,
so there is nothing to search through here.

### What a run returns

```json
{
  "channel": "telegram",
  "channel_title": "Telegram News",
  "channel_url": "https://t.me/s/telegram",
  "username": "telegram",
  "description": "The official Telegram on Telegram.",
  "subscribers_display": "9.82M",
  "counters": {
    "subscribers": "9.82M",
    "photos": "14",
    "videos": "225",
    "links": "372"
  },
  "newest_message_number": 454
}
```

Every row carries the same eight fields: `channel`, `channel_title`, `channel_url`, `username`,
`description`, `subscribers_display`, `counters` and `newest_message_number`. A value the channel
does not state is returned as `null` rather than omitted, with one deliberate exception:
`counters` is an empty object rather than `null` when a header states no counters at all.

`channel` is the username the row was requested under, cleaned back to the bare handle, and
`username` is the handle as Telegram itself states it on the page. The two are normally identical,
and comparing them is worth doing when a channel is being resolved under a name that may have
changed. `channel_title` is the display title, which an owner can change at any time; `channel` is
the stable key.

### Accepted input

`channels` is required and is the whole input. It takes one or more channels, one per line, in
whatever form is closest to hand: `telegram`, `@telegram`, `t.me/telegram`,
`https://t.me/s/telegram` and `https://t.me/telegram/435` all reduce to the same username.
Duplicates are removed before the first lookup, so a channel written three ways is resolved once
and charged once.

There is no cap and no cursor, because there is nothing to page through. One channel produces one
row.

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

### Questions

**Why is `counters` a map instead of fixed columns?**
Because which counters exist varies per channel. Telegram renders between one and four of them in
a channel header, covering subscribers, photos, videos and links, and a channel that has never
posted a video has no `videos` counter at all. Fixed columns would either state `null` for counters
a channel does not have or drop a label Telegram introduces later, and both misreport the page. A
key that is present should be read; a key that is absent means the channel states no such counter,
which is not the same as zero. `subscribers_display` is lifted out under a predictable name because
it is the counter almost every run is after.

**Why is `subscribers_display` text such as `9.82M` rather than a number?**
Because that is all the public page publishes. There is no exact subscriber count anywhere an
anonymous reader can reach, so `9.82M` is the measurement, and expanding it to `9820000` would
invent three digits Telegram never gave with nothing downstream able to tell them from measured
ones. The value is passed through as it arrived, and the `_display` suffix states the type before
anyone parses it. It is `null` on a channel whose header states no subscriber counter.

**What happens to a channel that is private, misspelled, or actually a group?**
It is skipped, and the run carries on with the rest of the list. Telegram serves the same join page,
with HTTP 200, for a channel that does not exist, for a private channel, for a group and for a
chat, so those four cases are one answer from outside and cannot be told apart. The run logs a
warning naming the channel, and a channel that produced no row is not charged for; a list of four
hundred channels should not be lost to one retired name. An entry that is not a Telegram name at
all is dropped the same way, before any lookup: a name is 5 to 32 characters, starts with a letter,
and then uses letters, digits or underscores.

**Is `newest_message_number` the number of posts a channel has published?**
It is the newest post's position in the channel's own numbering, which counts up from 1. That makes
it a reasonable proxy for how much a channel has published, and an exact answer to whether anything
has been posted since a previous run: store it, compare it next time, and a channel whose number
has not moved has published nothing. It is a position in the channel's numbering rather than a
count of the posts still visible, so treat it as an upper bound on how much a channel holds.

**Does listing the same channel twice cost twice?**
No. `@telegram`, `t.me/telegram` and `https://t.me/s/telegram` are one channel written three ways,
and the list is reduced to unique names before the first lookup. One row is produced and one row is
charged.

**Are reactions, engagement rates or post-level statistics available here?**
No, and not from the posts Actor either. The public preview page states the header counters listed
above and nothing more; reactions and comment threads are not on it, so neither is reachable
without an account. A post's view count is the one engagement figure the preview does carry, and
[Telegram Channel Scraper](https://apify.com/thenetaji/telegram-channel-scraper) collects it per
post.

**Can channels be found by keyword or topic rather than named?**
No. Telegram publishes no public directory of channels and no list this Actor could walk, so the
names have to come from somewhere else: a newsletter, a competitor's link list, a spreadsheet
already in hand. This is a property of Telegram rather than a gap I intend to close later.

### Related Actors

[Telegram Channel Scraper](https://apify.com/thenetaji/telegram-channel-scraper) exports the posts
themselves, with each post's text, media, view count, timestamp, and what it was forwarded from or
replying to. Resolving a list here first and exporting only the channels worth reading is the
cheaper order of operations; `newest_message_number` from a row here is also the value that Actor
takes as `after` to collect only what is new.

# Actor input Schema

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

Public Telegram channels to read, one per line. Any form is accepted: a username, an @handle, a t.me link, a preview link, or a link to a single post. `telegram`, `@telegram`, `https://t.me/telegram`, `https://t.me/s/telegram` and `https://t.me/telegram/435` all resolve to the same channel, and a channel listed twice is read once.

The channel name has to be known in advance. Telegram publishes no directory, no sitemap and no robots.txt, so channels cannot be enumerated and no list can be offered here.

Only public channels with a web preview can be read. Private channels, groups and user chats all serve the same join page; a run logs a warning naming each one and continues through the rest of the list.

## Actor input object example

```json
{
  "channels": [
    "telegram"
  ]
}
```

# Actor output Schema

## `dataset` (type: `string`):

All records scraped by this run

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

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

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,thenetaji/telegram-channel-info-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/qWvX4cSqxxrpJ0uZ6/builds/ByptZBeFIltjiK0T4/openapi.json
