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

Scrapes posts from public Telegram channels with views, reactions, media and links, searches inside channels or finds channels by keyword, and adds exact subscriber counts.

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

## Pricing

from $1.00 / 1,000 rows

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

### What does Telegram Channel Scraper do?

**Telegram Channel Scraper** collects posts from **public Telegram channels**:
the full text, **date, views, reactions, paid Stars, photos, videos, files, polls,
link previews, forwards and replies**, plus each channel's **exact subscriber
count**, title, description and photo. Paste channel links, single post links
or a search inside a channel. You can also **search all of Telegram by keyword**,
and every post you get back really contains your keyword.

Try it with the prefilled channel: open the Actor, click **Start**, and the
first 20 posts arrive in a few seconds. Because it runs on the Apify platform,
you also get API access, scheduled runs, integrations (Google Sheets, Make,
Zapier, webhooks), run monitoring and automatic retries through Apify Proxy
when [Telegram](https://telegram.org) is slow to answer.

### Why scrape Telegram channels?

- **Media and news monitoring**: follow news, politics or industry channels
  and get every new post as structured data.
- **Crypto and market research**: track what signal, project and exchange
  channels post, and how many views and reactions each post earns.
- **Brand and keyword tracking**: find every public channel that mentions
  your brand, product or hashtag, with posts that really contain it.
- **Audience research**: compare channels by exact subscriber count, views
  per post and reactions.
- **Archiving and AI datasets**: save a channel's history with text, links
  and media URLs for analysis or model training.

### How to scrape Telegram channels

1. Find a public channel in Telegram and copy its link, such as
   `https://t.me/durov`. A plain `@durov` works too.
2. Paste it into **Telegram links**, one link per line.
3. Optionally, paste a link to a single post (`https://t.me/durov/548`) or a
   search inside a channel. To get a search link, open the channel at
   `https://t.me/s/durov`, type in its search box, and copy the address bar.
4. Set **Max posts per link** and, if you only want recent posts,
   **Only posts newer than** (a date or an age such as `7 days`).
5. Click **Start**, then download the results when the run finishes.

To find channels you don't know yet, type words into **Find channels by
keyword** instead. The Actor looks up public channels about each keyword and
saves only their posts that contain every word of it.

### Input

Everything is set on the Input tab. In JSON, the input looks like this:

```json
{
    "startUrls": [
        "https://t.me/s/durov",
        "https://t.me/telegram/441",
        "https://t.me/s/tginfo?q=bot"
    ],
    "maxPostsPerChannel": 100,
    "newerThan": "30 days",
    "includeChannelInfo": true,
    "keywords": ["bitcoin etf"],
    "maxChannelsPerKeyword": 5
}
```

| Field | What it does |
|---|---|
| `startUrls` | Channel links (`t.me/name`, `t.me/s/name`, `@name`), single post links (`t.me/name/123`) or in-channel search links (`t.me/s/name?q=word`). |
| `maxPostsPerChannel` | Stops after this many posts per link, newest first. Default: 100. Set `0` to save only channel profiles. |
| `newerThan` | Skips posts older than a date (`2026-09-01`) or an age (`7 days`, `12 hours`, `2 weeks`). |
| `includeChannelInfo` | Adds one profile row per channel with its exact subscriber count. Default: on. |
| `keywords` | Optional. Finds public channels about each keyword and saves their posts that contain it. |
| `maxChannelsPerKeyword` | How many channels to search for each keyword, from 1 to 10. Default: 5. |
| `proxyConfiguration` | Optional; leave it empty. Telegram answers the Actor directly, and if it is ever refused, the Actor retries through Apify datacenter and then residential proxies by itself. |

### Output

Each post and each channel profile becomes one row. Here is a real post, with
its long media links shortened:

```json
{
    "type": "post",
    "channel": "durov",
    "channelTitle": "Pavel Durov",
    "postId": 537,
    "url": "https://t.me/durov/537",
    "date": "2026-08-03T07:19:56+00:00",
    "isEdited": false,
    "text": "🧠 The 2026 International Olympiad in Artificial Intelligence starts today.\n\nAs a token of support for those who will reinvent our civilization, we'll issue 🏆 240 exclusive Intelligence Cups to the winners. …",
    "links": [],
    "views": 3610000,
    "reactions": [
        { "emoji": null, "customEmojiId": "5399847211989246390", "count": 39400 },
        { "emoji": null, "customEmojiId": "5936157098181135162", "count": 11200 }
    ],
    "paidStars": 15500,
    "media": [
        { "type": "photo", "url": "https://cdn4.telesco.pe/file/OITBwTjjdBxK…jpg" }
    ],
    "linkPreview": null,
    "poll": null,
    "forwardedFrom": null,
    "replyTo": null,
    "author": "Pavel Durov",
    "matchedKeyword": null,
    "sourceUrl": "https://t.me/s/durov",
    "scrapedAt": "2026-10-01T18:11:30.442713+00:00"
}
```

And the channel's profile row:

```json
{
    "type": "channel",
    "channel": "durov",
    "title": "Pavel Durov",
    "description": "Founder of Telegram.",
    "subscribers": 10557247,
    "isVerified": true,
    "photoUrl": "https://cdn4.telesco.pe/file/Wy6pjko8IMI…jpg",
    "url": "https://t.me/durov",
    "scrapedAt": "2026-10-01T18:11:29.958551+00:00"
}
```

The Output tab has two views, **Posts** and **Channel profiles**. You can
download the dataset in various formats such as JSON, HTML, CSV, or Excel.

### Data fields

Post rows (`type` is `post`):

| Field | Description |
|---|---|
| `channel` | The channel's username. |
| `channelTitle` | The channel's display name. |
| `postId` | The post's number in the channel. |
| `url` | Link to the post. |
| `date` | When it was posted (UTC, ISO 8601). |
| `isEdited` | `true` when the post was edited after posting. |
| `text` | The full post text, with line breaks and emoji. |
| `links` | Web addresses linked from the text. |
| `views` | View count. Telegram rounds counts above 1,000 (for example 1.87M becomes 1870000). |
| `reactions` | Each reaction with its `emoji` (or `customEmojiId` for custom emoji) and `count`. |
| `paidStars` | Telegram Stars paid as reactions. |
| `media` | Photos, videos, animations, files, audio and stickers: `type`, `url`, plus `thumbnailUrl` and `durationSec` for videos, `title` and `size` for files, and `title` and `performer` for audio. |
| `linkPreview` | The preview card of a shared link: `url`, `siteName`, `title`, `description`, `imageUrl`. |
| `poll` | A poll's `question`, `type` and `options` with their vote `percent`. |
| `forwardedFrom` | The original channel or author of a forwarded post: `name` and `url`. |
| `replyTo` | Link to the post this one replies to. |
| `author` | The author signature, on channels that sign posts. |
| `matchedKeyword` | The keyword or in-channel search the post matched. |
| `sourceUrl` | The link the post was found through. |
| `scrapedAt` | When the row was saved. |

Channel rows (`type` is `channel`): `channel`, `title`, `description`,
`subscribers` (exact), `isVerified`, `photoUrl`, `url` and `scrapedAt`.

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

Telegram Channel Scraper uses **pay-per-event** pricing, so you pay only for
results:

- **$1.00 per 1,000 rows**: each post or channel profile saved is one row.
- **$0.01 per keyword search** that returns posts. Keyword searches that find
  nothing are free.
- A tiny fee per run start.

For example, the latest 100 posts of 10 channels plus their profiles
(1,010 rows) cost about $1.01. Apify's free plan includes $5 of monthly
credit, enough for roughly 5,000 posts. Links that return nothing are never
saved as rows, so you are not charged for them. If you set a maximum cost for
a run, the Actor stops as soon as it is reached.

### Tips for scraping Telegram

- **Use `newerThan` for monitoring.** Schedule a daily run with `1 day` to get
  only new posts from your channels.
- **Profiles only:** set `maxPostsPerChannel` to `0` to check the subscriber
  counts of a long list of channels quickly and cheaply.
- **Search inside a channel** when you need older posts on one topic:
  Telegram's search finds matches anywhere in the channel's history. It returns
  up to about 20 of the newest matches per search, so use several searches for
  more.
- **Hashtags work** in in-channel searches: `https://t.me/s/durov?q=%23Telegram`.
- **Keyword search is slower** than pasting links, because each keyword first
  has to find channels. Paste channel links whenever you know them.
- Each post is saved only once per run, even when several links lead to it.

### FAQ, disclaimers and support

**Which channels can be scraped?** Public channels that show their posts on
the web at `t.me/s/<name>`. Most public channels do. Private channels, invite
links, groups, bots and personal accounts cannot be read. A channel that hides
its web preview still gets its profile row, but its posts can only be read in
the Telegram app.

**Why are view counts rounded?** Telegram itself only shows rounded counts
above 1,000, such as 1.87M. The Actor turns them into numbers.

**What happens to links that return nothing?** They are not saved as rows,
so you are not charged for them. Each one is listed with its reason in the
`FAILED_INPUTS` record of the run's key-value store, and the run's status
message gives the counts. A run fails only when every input failed because
Telegram could not be reached.

**Are media links permanent?** Photo and video links point to Telegram's
content servers and may stop working after a while. Download the files soon
after the run if you need to keep them.

**Is it legal to scrape Telegram?** This Actor collects only posts and
profiles that channels publish openly on the web. It does not read private
chats, groups or comments. Posts can still contain personal data, so you are
responsible for making sure your use complies with Telegram's Terms of Service
and with data protection laws such as the GDPR. If in doubt, ask a lawyer.

**Found a problem or need a custom solution?** Open an issue on the
**Issues** tab and we will look into it. Custom scrapers and data feeds are
available on request.

# Actor input Schema

## `startUrls` (type: `array`):

Public channel links, one per line. Paste a channel (https://t.me/durov or https://t.me/s/durov, or just @durov) to get its newest posts, a single post (https://t.me/durov/548), or a search inside a channel (https://t.me/s/durov?q=privacy — open the channel at t.me/s/…, search, and copy the address bar; hashtags work too). Private invite links, groups and personal accounts cannot be read and are listed in the FAILED_INPUTS record.

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

Stops after this many posts for each link, newest first (and for each channel found for a keyword). Set 0 to save only channel profiles. Telegram's in-channel search returns at most about 20 of the newest matching posts, so search links stop there.

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

Skips posts older than this date (for example 2026-09-01) or age (for example 7 days). Leave empty to read as far back as the limit above allows. Single-post links are always saved.

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

Adds one row per channel with its title, description, photo, verified badge and exact subscriber count. For channels found by keyword, only channels with a matching post get a profile row.

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

Words or phrases, one per line, such as bitcoin etf. A post is saved only when every word appears in its text, link preview, poll or file name.

## `maxChannelsPerKeyword` (type: `integer`):

How many of the channels found for each keyword are searched, most relevant first. Up to 10.

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

Leave this empty: Telegram answers the Actor directly, and if it ever refuses, the Actor retries through Apify's datacenter and then residential proxies on its own.

## Actor input object example

```json
{
  "startUrls": [
    "https://t.me/s/durov"
  ],
  "maxPostsPerChannel": 20,
  "includeChannelInfo": true,
  "keywords": [],
  "maxChannelsPerKeyword": 5,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `dataset` (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 = {
    "startUrls": [
        "https://t.me/s/durov"
    ],
    "maxPostsPerChannel": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("mina_safwat/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 = {
    "startUrls": ["https://t.me/s/durov"],
    "maxPostsPerChannel": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("mina_safwat/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 '{
  "startUrls": [
    "https://t.me/s/durov"
  ],
  "maxPostsPerChannel": 20
}' |
apify call mina_safwat/telegram-channel-scraper --silent --output-dataset

```

## MCP server setup

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