# Telegram Channel Scraper (`cyber1nj3ct0r/telegram-channel-scraper`) Actor

Scrape public Telegram channels without a login or API key. One row per message: text, date, views, reactions, media, links, hashtags, forwards and replies, plus the channel's details. Filter by date or keyword. $0.50 per 1,000 messages.

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

## Pricing

from $0.40 / 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.
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?

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

### What does Telegram Channel Scraper do?

Telegram Channel Scraper reads public Telegram channels and turns their messages into a table. Give it channel names such as `durov` or links such as `https://t.me/telegram`, and you get one row per message with its **text, date, views, reactions, photos and videos, links, hashtags, forwards and replies**, plus one row with the channel's own details: title, description and number of subscribers. Export to Excel, CSV or JSON, or send it on to another app.

There is nothing to set up. No Telegram account, no phone number, no API key and no bot token: the tool reads the public web preview that Telegram shows to anyone at `t.me/s/channelname`.

- Every message of a channel, newest first, as far back as you ask
- Filter by date: the last 24 hours, a month in the past, or any period in between
- Filter by keyword or hashtag, using Telegram's own channel search
- Many channels in one run, each message once
- Text as plain text and as HTML, with the links, hashtags and mentions listed
- Views, reactions with their counts, forwarded-from, reply-to, edited mark and author signature
- Photos, videos and link previews with their addresses, video lengths and thumbnails
- Channels that do not exist or have no public preview give a clear error row and never stop the run

### What data do you get?

Each message is one row:

| Field | Example |
|---|---|
| Channel | `durov` and the channel's title |
| Message | `https://t.me/durov/531`, number `531` |
| Date | `2026-07-16T20:45:25.000Z` |
| Text | the message as plain text, and as HTML (`textHtml`) |
| Views | `5830000` (Telegram shows `5.83M`) |
| Reactions | `[{"emoji": "👍", "count": 54600, "paid": false}]` |
| Forwarded from / Reply to | the source's name and link, the replied message's number, link and text |
| Author | the signature on the post, for channels that sign their posts |
| Edited | `true` or `false` |
| Links, hashtags, mentions | the addresses, `#tags` (without the sign) and `@names` in the text |
| Media | photos and videos with address, thumbnail and length in seconds; voice messages, files, stickers, polls and locations where the preview shows them |
| Link preview | the card Telegram builds for a link: address, site, title, description, image |
| Buttons | link buttons under the post |
| Keyword | the keyword whose search found the message |

The **channel row** (`type: "channel"`) has the channel's title, description, subscribers, the counts of photos, videos, files and links that Telegram shows, the verified mark and the profile picture. It comes first for each channel and counts as one result. Turn it off with **Include a row with the channel's details**, or ask for nothing else with **Channel details only**: a quick way to compare the size of many channels.

### How to scrape a Telegram channel

1. Under **Channels**, add the channels: user names, `@names` or links, one per line.
2. Optionally set **Maximum messages per channel**, **Posted from / until** or **Keywords**.
3. Press **Start**.
4. Export the results as Excel or CSV, or connect them to Google Sheets, Slack, Make or Zapier.

### How much does it cost to scrape Telegram?

You pay for results, not for time: **$0.50 per 1,000 messages**. Apify subscribers on the Silver plan pay $0.45 and on the Gold plan $0.40 per 1,000 messages. Each run also has a start fee of $0.00005.

| Messages returned | Cost |
|---|---|
| 100 | $0.05 |
| 1,000 | $0.50 |
| 10,000 | $5.00 |
| 100,000 | $50.00 |

Apify's free plan includes $5 of credit each month, which covers about 10,000 messages. A channel row and a row for a channel that could not be read each count as one result. Messages left out by your filters are not charged. Set a maximum cost for the run in Apify Console and the tool stops there and keeps what it has read.

### Input

The only required field is **Channels**. The other options:

- **Maximum messages per channel**: keeps the newest messages of each channel. Telegram shows 20 messages per page and answers Apify's servers in a few seconds per page: in a test on Apify, 1,864 messages from three channels took 6.5 minutes.
- **Posted from** and **Posted until**: a date, or a period such as `7 days` or `24 hours`. A plain end date includes the whole day. Reading a period far in the past is fast: the tool jumps to the end date instead of reading every newer page.
- **Keywords**: words, phrases or hashtags such as `bitcoin` or `#news`. Telegram's own channel search finds the messages, so a match is what Telegram counts as one. Keywords are searched one after the other (up to 25), and a message found by several is returned once.
- **Include a row with the channel's details** and **Channel details only**.
- **Time limit per request** and **User-Agent** under More options.

### Output example

```json
{
    "type": "message",
    "channel": "example_news",
    "channelTitle": "Example News",
    "messageId": 4812,
    "url": "https://t.me/example_news/4812",
    "date": "2026-10-22T17:40:10.000Z",
    "text": "Central bank holds rates (Score: 155 in 2 hours)\n\nLink: https://example.com/rates",
    "textHtml": "<b>Central bank holds rates</b> (Score: 155 in 2 hours)<br><br>Link: <a href=\"https://example.com/rates\">https://example.com/rates</a>",
    "views": 2110,
    "reactions": [{ "emoji": "👍", "customEmojiId": null, "count": 36, "paid": false }],
    "forwardedFrom": null,
    "replyTo": null,
    "author": null,
    "edited": false,
    "links": ["https://example.com/rates"],
    "hashtags": ["economy"],
    "mentions": [],
    "media": [{ "type": "photo", "url": "https://cdn4.telesco.pe/file/example.jpg", "thumbnail": null, "duration": null }],
    "linkPreview": { "url": "https://example.com/rates", "siteName": "Example", "title": "Central bank holds rates", "description": "The bank kept its rate at 3.5 %.", "imageUrl": null },
    "buttons": [],
    "keyword": null
}
```

A channel that cannot be read gives one row with an `error`: `NO_PUBLIC_PREVIEW`, `CHANNEL_NOT_FOUND`, `INVALID_INPUT` (a private invite link or something that is not a channel), `RATE_LIMITED`, `ROBOTS_DISALLOWED` or a network error. If a page fails in the middle of a channel, the messages read so far are kept and the error row says how many.

### What can you use it for?

- Monitor news, announcement and crypto channels, and get new posts into Slack, e-mail or your own app on a schedule
- Collect posts for sentiment analysis, research and AI tools
- Track which topics, hashtags and links a channel pushes, and how many views and reactions they get
- Compare the size and activity of channels in a niche
- Archive a channel before posts are deleted

Schedule the run in Apify Console, for example every hour with **Posted from** set to `1 hour`, to get only the new messages each time.

### Use it from the API

```bash
curl -X POST "https://api.apify.com/v2/acts/cyber1nj3ct0r~telegram-channel-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"channels": ["durov", "https://t.me/s/telegram"], "maxMessagesPerChannel": 200, "postedFrom": "7 days"}'
```

The same works from Python, JavaScript, Make, Zapier and n8n through Apify's integrations.

### FAQ

#### Which channels can it read?

Public channels whose preview opens at `t.me/s/channelname` in a browser without logging in. Private channels, invite links, groups, bots and people's accounts have no such page, and the tool says so in an error row. A channel whose owner turned the web preview off cannot be read either. Telegram gives the same answer for a name nobody has taken, so the error also covers a misspelled name.

#### Do I need a Telegram account or an API key?

No. The tool reads the same page a visitor sees. It identifies itself in its User-Agent, follows the site's robots.txt, asks for about one page per second, waits when Telegram asks it to slow down, and uses no logins, cookies or proxies.

#### How far back can it go?

As far as the channel's public preview does. In tests it read @durov and @telegram back to their first message. Set **Maximum messages per channel** and the dates to limit the cost.

#### Why are the view counts rounded?

Telegram shows `5.83M` or `2.1K`, not exact numbers, and so do the subscribers and reactions. The tool turns them into numbers (`5830000`) but cannot know more than the page says.

#### What does the media type `unsupported` mean?

For some posts the preview hides part of the content behind a "Please open Telegram to view this post" box. Voice messages, files, polls and some other items can be hidden this way. The tool can only return what the preview shows, so the row then has a media entry of type `unsupported` with that note, and nothing else about the hidden part. Albums sent together appear as one row with all their photos, numbered with the first message.

#### Do the photo and video links last?

They are Telegram's own file addresses and can stop working after a while, and the videos carry a token. Download what you need soon after the run. Videos that are too big for the preview have a thumbnail and a length but no file address.

#### Does it get comments, member lists or private chats?

No. It returns the posts of public channels as the preview shows them: no comments under posts, no list of members and nothing from private chats.

#### Is it allowed to scrape Telegram?

The tool reads only pages that anyone can open without logging in. Messages can still contain personal data and are copyrighted by their authors: you are responsible for how you store, use and share them, under the laws that apply to you and Telegram's terms.

#### Something does not work

Open an issue on the **Issues** tab with the channel you tried. Telegram changes its pages from time to time, and every report is read and answered.

# Actor input Schema

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

Public channels, one per line: a user name such as <code>durov</code> or <code>@durov</code>, or a link such as <code>https://t.me/durov</code> or <code>https://t.me/s/durov</code>. Only channels whose messages anyone can read at <code>t.me/s/name</code> work; private channels and invite links do not.

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

Keep at most this many messages of each channel, newest first. You pay per message returned, so this also caps the cost. Telegram shows 20 messages per page, so a channel of 1,000 messages takes about 50 requests.

## `postedFrom` (type: `string`):

Keep only messages posted on or after this date. Pick a date or a period such as <code>7 days</code> or <code>24 hours</code>.

## `postedUntil` (type: `string`):

Keep only messages posted on or before this date (a plain date includes the whole day). To read a period in the past, set both dates; the tool jumps straight to the end date instead of reading every newer page.

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

Only messages that Telegram's own channel search finds for these words or phrases, such as <code>bitcoin</code> or <code>#news</code>. Several keywords are searched one after the other, and a message found by more than one is returned once, with the keyword that found it. Leave empty to read all messages.

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

Add one row per channel with its title, description, number of subscribers, counts of photos, videos, files and links, and the verified mark. It counts as one result.

## `channelInfoOnly` (type: `boolean`):

Return only the row with the channel's details and no messages. Quick way to check the size of many channels.

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

How long to wait for one page before giving up.

## `userAgent` (type: `string`):

The name the tool sends with each request. Leave empty to use the tool's own name, which tells site owners what is visiting. Set your own only for sites you run or have permission to use.

## Actor input object example

```json
{
  "channels": [
    "telegram"
  ],
  "maxMessagesPerChannel": 20,
  "includeChannelInfo": true,
  "channelInfoOnly": false,
  "requestTimeoutSecs": 30
}
```

# Actor output Schema

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

One row per message with its text, date, views, reactions, media and links, and one row per channel with its details.

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

Each channel read: pages read, messages saved, and the problem if it could not be read.

# 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"
    ],
    "maxMessagesPerChannel": 20
};

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

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

```

## MCP server setup

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