# Telegram Channel Info Scraper (`tmedge/telegram-channel-info-scraper`) Actor

Resolve public Telegram channels, groups, bots and users by username. Get type, verification, description, subscriber count and avatar hash. No login required.

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

## Pricing

from $1.00 / 1,000 entity resolveds

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

Resolve public Telegram channels, groups, bots and users by username — without a Telegram account, API key or browser.

This Actor parses the public `t.me` pages and returns one dataset row per requested username. It is useful for lead enrichment, channel vetting, ad-placement research and OSINT workflows.

### What it returns

For each username:

- Entity type: `channel`, `group`, `bot`, `user` or `unknown`
- Title and public description
- `confirmed`: `true` when a titled entity page or channel preview was found; `false` for an unconfirmed contact page
- Telegram verification badge (`verified`)
- Subscriber / member / monthly-user count when publicly visible
- Avatar URL
- Optional avatar SHA-256 hash and Base64 data
- Per-row status: `ok`, `not_found`, `invalid_input`, `rate_limited` or `error`

Failed rows do not stop the run. The Actor keeps going and reports the error per username.

### Input

```json
{
  "usernames": ["telegram", "@durov", "https://t.me/examplebot"],
  "downloadAvatar": false,
  "maxConcurrency": 5,
  "requestTimeoutSecs": 20,
  "maxRetries": 2,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

- `usernames` — required. Usernames, `@mentions`, `t.me/...` links and `telegram.me/...` links are accepted. `t.me/s/...` preview links are normalized to the username; private invite links are rejected.
- `downloadAvatar` — optional. Adds avatar SHA-256 and Base64 to successful rows. This triggers the optional `avatar-downloaded` charge.
- `maxConcurrency` — optional, 1–20. Default `5`.
- `requestTimeoutSecs` — optional, 5–60. Default `20`.
- `maxRetries` — optional, 0–5. Retries rate limits, timeouts and server errors. Default `2`.
- `proxyConfiguration` — optional. Enable Apify Proxy if `t.me` blocks the platform IPs.

### Output

Successful row:

```json
{
  "input": "telegram",
  "username": "telegram",
  "type": "channel",
  "title": "Telegram News",
  "confirmed": true,
  "verified": true,
  "description": "The official Telegram on Telegram. Much recursion. Very Telegram. Wow.",
  "subscribers": 9174802,
  "avatar_url": "https://cdn4.telesco.pe/file/...jpg",
  "avatar_hash": null,
  "avatar_base64": null,
  "status": "ok",
  "http_status": 200,
  "error": null,
  "attempts": 1,
  "fetched_at": "2026-11-07T12:00:00+00:00",
  "updated_at": "2026-11-07T12:00:00+00:00"
}
```

Error row:

```json
{
  "input": "nonexistent_abc12345",
  "username": "nonexistent_abc12345",
  "status": "not_found",
  "http_status": 404,
  "error": "Telegram entity not found",
  "attempts": 1,
  "fetched_at": "2026-11-07T12:00:00+00:00"
}
```

A run summary is stored in the default key-value store under the `SUMMARY` key.

### Pricing setup

This Actor is designed for Apify's pay-per-event pricing. In Apify Console → Actor → **Publication → Monetization**, configure:

| Event | Suggested price | When it is charged |
|---|---:|---|
| `entity-resolved` | `$0.001` per event (`$1 / 1,000`) | One charge per **confirmed** entity (titled page or recovered channel preview) |
| `avatar-downloaded` | `$0.0005` per event (`$0.50 / 1,000`) | One charge per successfully downloaded avatar |
| `apify-actor-start` | keep the default | Actor start |

Remove `apify-default-dataset-item`, or set its price to `0`. Otherwise Apify will also charge the synthetic dataset event for error rows and may combine it with the explicit event.

Only confirmed resolutions are charged. `not_found`, `invalid_input`, other error rows, and unconfirmed contact pages (`confirmed: false`) are free.

You can change these prices at any time; Apify applies price increases after a 14-day notice period.

### Limits and compliance

- Only public `t.me` pages are accessed. No login, no private groups, no member lists, no message history.
- Telegram may rate-limit or block cloud IP ranges. Lower `maxConcurrency` first; if that is not enough, enable Apify Proxy.
- Some usernames resolve to user pages without a public title. Those rows have `type: "user"`, `title: null`, `description: null` and `confirmed: false`; they are free and are not 404s.
- `t.me` returns a contact page for any valid-looking username, so `type: "user"` with `confirmed: false` does not guarantee that the account exists. Channels are confirmed through the `t.me/s/{username}` preview.
- When `t.me` returns a degraded contact page for a channel, the Actor automatically falls back to the public `t.me/s/{username}` preview. Subscriber counts from that fallback are approximate (for example `9.17M`). If the preview also fails, the row stays `user` or `unknown`; retry with lower `maxConcurrency` or enable Apify Proxy.
- HTML changes on Telegram can affect parsing. The Actor returns per-row errors instead of failing the whole batch.
- Data freshness depends on the public page at request time. Subscriber counts and descriptions are snapshots.
- This Actor is not affiliated with, endorsed by or sponsored by Telegram. Users are responsible for complying with Telegram's terms and applicable law.

### Performance

- 1,000 mixed usernames: about 1–2 minutes.
- 5,000 channels: about 10 minutes; 512 MB memory is enough.
- Large batches need a longer run timeout. Use at least 1800 seconds, or split the input into smaller runs.
- When `t.me` rate-limits, the channel-preview fallback adds time but keeps channel results accurate.

### Local development

Requires Python 3.12+ and [uv](https://github.com/astral-sh/uv).

```bash
uv sync
uv run pytest
```

Run the Actor locally with the Apify CLI:

```bash
mkdir -p storage/key_value_stores/default
cat > storage/key_value_stores/default/INPUT.json <<'JSON'
{
  "usernames": ["telegram", "durov"],
  "downloadAvatar": false
}
JSON

npx -y apify-cli@1.11.0 run
```

### Deploy to Apify

This repository is connected to an Apify Actor. Pushes to `main` trigger a new build in Apify Console.

If you are not using the GitHub integration, you can still deploy manually:

```bash
npx -y apify-cli@1.11.0 login
npx -y apify-cli@1.11.0 push
```

Do not use both the GitHub integration and `apify push` for the same Actor — pick one source of truth.

### 中文说明

这是从 `t-me-edge` 的 Telegram 公开页面解析逻辑迁移出来的独立 Apify Actor。它不依赖原生产服务的 FastAPI、Redis 或部署环境，生产仓库不需要做任何改动。

- 输入用户名列表，按条输出实体信息；
- 只抓公开页面，不需要 Telegram 账号；
- 成功解析按 `entity-resolved` 事件计费，头像可选 `avatar-downloaded`；
- 失败行保留在数据集里，但不会中断整批任务。

# Actor input Schema

## `usernames` (type: `array`):

Telegram usernames, @mentions, or t.me links. Duplicates are removed automatically.

## `downloadAvatar` (type: `boolean`):

Download profile photos and return their SHA-256 hash and Base64 data. This uses the extra 'avatar-downloaded' event if you configure it.

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

Number of parallel requests. Higher values are faster but more likely to hit Telegram rate limits.

## `requestTimeoutSecs` (type: `integer`):

Timeout for each HTTP request.

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

Retries for rate limits, timeouts and server errors.

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

Optional. Use Apify Proxy if t.me blocks the platform IP addresses.

## Actor input object example

```json
{
  "usernames": [
    "telegram",
    "durov"
  ],
  "downloadAvatar": false,
  "maxConcurrency": 5,
  "requestTimeoutSecs": 20,
  "maxRetries": 2,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

One row per requested username. Successful rows contain entity data; failed rows contain an error status.

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

Counts of confirmed, unconfirmed, not-found, invalid and failed rows, plus duration and charge-limit status.

# 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 = {
    "usernames": [
        "telegram",
        "durov"
    ]
};

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

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

```

## MCP server setup

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