# Telegram Channel Scraper – Posts, Messages & Views, No Login (`openharvest/telegram-channel-scraper`) Actor

Telegram channel scraper for public channels, without login or API keys: posts and messages with text, views, reactions, photos, videos, polls, link previews, forwards and replies, plus channel info (subscribers, description). Search inside channels and filter by date.

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

## Pricing

from $1.50 / 1,000 post scrapeds

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 Scraper – Posts, Messages & Views, No Login

Telegram channel scraper for public channels, without login or API keys: posts and messages with text, views, reactions, photos, videos, polls, link previews, forwards and replies, plus channel info (subscribers, description). Search inside channels and filter by date.

**Price: $1.50 per 1,000 posts.** Channels that fail produce a free error row.

### What does Telegram Channel Scraper do?

Telegram Channel Scraper reads the official public web preview of a channel (`https://t.me/s/<channel>`) – the same page anyone can open in a browser – and turns it into clean, structured data:

- **Posts** – full text (with line breaks and emoji), optional original HTML, hashtags and outbound links
- **Views** – parsed into real integers (`"1.2K"` → `1200`, `"3.4M"` → `3400000`)
- **Reactions** – emoji + count for every reaction, including custom emoji and paid Star reactions
- **Media** – media type (photo, video, sticker, poll, voice, document, audio…) and direct media URLs (photos, video files, stickers), plus video thumbnails
- **Polls** – question, poll type and the percentage for each option
- **Link previews** – URL, site name, title, description and image
- **Forwards and replies** – the source channel of forwarded posts and the post a message replies to
- **Edited flag**, author signature, post URL and ISO date
- **Channel info** – title, @username, verified badge, description, subscribers, number of photos/videos/files/links and avatar URL

It walks back through the channel history page by page, so you can get the latest 20 posts or **the whole archive of thousands of posts**.

### Details

- **No login, no API keys, no phone number** – it reads only public pages, so your Telegram account is not involved.
- **Pay per result** – $1.50 per 1,000 posts, $0.002 per channel profile.
- **No browser** – plain HTTP requests. About 1,000 posts in under a minute in our tests.
- **Errors are free** – channels that don't exist, bots, groups and channels without a public preview produce an error row that is not charged.
- **Cost control** – set *Max posts per channel*, a date limit and Apify's *Max cost per run*; the Actor stops when your budget is reached.

### Use cases

- **Media monitoring & news tracking** – follow news, political or crypto channels and pull new posts on a schedule.
- **Marketing & competitor analysis** – compare views, reactions and posting frequency of competitor channels.
- **Influencer research** – check subscriber counts and real engagement (views/reactions per post) before buying ads.
- **Crypto & trading signals** – collect posts from public signal channels into a spreadsheet or database.
- **Academic research & OSINT** – build datasets of public channel content for NLP, sentiment or propaganda research.
- **AI / LLM pipelines** – feed fresh channel content into RAG, summarization or classification workflows.

### How to scrape Telegram channels

1. Click **Try for free** / **Start**.
2. Enter one or more channels in **Telegram channels** – `durov`, `@durov` or `https://t.me/durov` all work.
3. Optionally set **Max posts per channel**, **Only posts newer than** (e.g. `7 days` or `2025-01-01`) and a **Search** keyword.
4. Click **Start** and download your data as JSON, CSV, Excel, XML or HTML – or connect it to Make, Zapier, Google Sheets, Slack, webhooks or the Apify API.

### Input

| Field | Type | Description |
|---|---|---|
| `channels` | array of strings | **Required.** Channel usernames or links (`durov`, `@durov`, `https://t.me/durov`, `https://t.me/s/durov`). |
| `maxPostsPerChannel` | integer | Max posts per channel, newest first. `0` = whole history. Default `100`. |
| `onlyNewerThan` | string | Skip older posts. Absolute date (`2025-01-01`) or relative (`7 days`, `2 weeks`, `3 months`). |
| `searchQuery` | string | Only posts containing this keyword or #hashtag. |
| `includeChannelInfo` | boolean | Add one channel-profile item per channel. Default `true`. |
| `includeTextHtml` | boolean | Also save the original post HTML in `textHtml`. Default `false`. |
| `proxyConfiguration` | object | Optional proxy. Not needed in normal use. |

Example input:

```json
{
    "channels": ["telegram", "durov", "https://t.me/bloomberg"],
    "maxPostsPerChannel": 200,
    "onlyNewerThan": "30 days",
    "includeChannelInfo": true
}
```

### Output

Each dataset item has a `type`: `post`, `channel` or `error`. Real sample output (shortened):

**Post**

```json
{
    "type": "post",
    "channel": "durov",
    "channelTitle": "Pavel Durov",
    "postId": 540,
    "url": "https://t.me/durov/540",
    "date": "2026-08-10T09:29:58.000Z",
    "text": "🇺🇿 The 2026 International Olympiad in Informatics starts today in Tashkent.\n\n🏆 The IOI is the ultimate coding competition for high-school students. ...",
    "views": 4550000,
    "author": "Pavel Durov",
    "edited": false,
    "forwardedFrom": null,
    "replyTo": null,
    "hasMedia": true,
    "mediaType": "photo",
    "mediaUrls": ["https://cdn4.telesco.pe/file/dWETKtgBqJjVJf6v9r4y...jpg"],
    "thumbnailUrls": [],
    "documents": [],
    "poll": null,
    "linkPreview": null,
    "reactions": [
        { "emoji": "⭐", "customEmojiId": null, "paid": true, "count": 9110 },
        { "emoji": null, "customEmojiId": "5373223594484587136", "paid": false, "count": 42500 },
        { "emoji": null, "customEmojiId": "5399847211989246390", "paid": false, "count": 15600 }
    ],
    "reactionsTotal": 77210,
    "hashtags": [],
    "links": [],
    "scrapedAt": "2026-10-07T18:06:46.386Z"
}
```

**Channel info**

```json
{
    "type": "channel",
    "channel": "durov",
    "title": "Pavel Durov",
    "username": "durov",
    "url": "https://t.me/durov",
    "verified": true,
    "description": "Founder of Telegram.",
    "subscribers": 10500000,
    "photosCount": 102,
    "videosCount": 46,
    "filesCount": null,
    "linksCount": 200,
    "avatarUrl": "https://cdn4.telesco.pe/file/e2rpvz6z6aZTf...jpg"
}
```

**Error (free)**

```json
{
    "type": "error",
    "channel": "nodejs_ru",
    "url": "https://t.me/nodejs_ru",
    "errorCode": "GROUP_NO_PREVIEW",
    "error": "@nodejs_ru is a group/chat. Telegram does not provide a public web preview for groups, so its messages can't be scraped without login."
}
```

Possible `errorCode` values: `NOT_FOUND`, `BOT`, `GROUP_NO_PREVIEW`, `CHANNEL_NO_PREVIEW`, `NO_PREVIEW`, `INVALID_INPUT`, `SCRAPE_FAILED`.

Other post fields you may see: `poll` (`question`, `type`, `options[{text, percent}]`), `linkPreview` (`url`, `siteName`, `title`, `description`, `imageUrl`), `forwardedFrom` (`name`, `url`, `username`), `replyTo` (`postId`, `url`, `author`, `text`), `documents` (`title`, `extra`), `textHtml`.

`mediaType` is one of `photo`, `video`, `sticker`, `poll`, `voice`, `audio`, `document`, `location`, `mixed` (album with several kinds), `unsupported` (media Telegram only shows inside the app) or `null` (text-only post).

The dataset has ready-made views in Apify Console: **Posts**, **Engagement**, **Media & links** and **Channel info & errors**.

### Pricing

This Actor uses **pay-per-event** pricing – you only pay for the data you get. Platform usage is included.

| Event | Price | When it is charged |
|---|---|---|
| `post` | **$0.0015** per post ($1.50 / 1,000) | Each post saved to the dataset |
| `channel-info` | **$0.002** per channel | Each channel profile item (only if *Include channel info* is on) |
| Errors | **Free** | Missing channels, bots, groups, channels without preview |

Examples:

| Job | Cost |
|---|---|
| 20 latest posts from 2 channels + channel info | 40 × $0.0015 + 2 × $0.002 = **$0.064** |
| 1,000 posts from 1 channel | **$1.50** (+ $0.002) |
| 10,000 posts from 10 channels | **$15.00** (+ $0.02) |

Tip: set **Max cost per run** in the run options – the scraper stops cleanly when your budget is reached.

### Use with AI agents (MCP)

Add the Actor to the [Apify MCP server](https://mcp.apify.com) (`https://mcp.apify.com?tools=openharvest/telegram-channel-scraper`) or let agents find it with `search-actors` ("telegram channel").

Example `call-actor` input for "What did the Telegram channel @durov post in the last two weeks, and which post got the most views?":

```json
{
    "channels": ["durov"],
    "onlyNewerThan": "14 days",
    "maxPostsPerChannel": 50,
    "includeChannelInfo": false
}
```

The agent reads `text`, `date`, `views` and `reactionsTotal`.

### FAQ

**Do I need a Telegram account or API key?**
No. The scraper only reads the public `t.me/s/` web preview that anyone can open without logging in.

**Can it scrape private channels or groups?**
No. Private channels, invite links (`t.me/+...`) and groups/chats have no public web preview. They are reported as a free `error` item. Some public channels also disable their web preview – those are reported as `CHANNEL_NO_PREVIEW`.

**How many posts can I get?**
As many as the channel shows publicly – set `maxPostsPerChannel` to `0` to get the full history. Posts that were deleted are skipped.

**How does search work?**
The scraper first uses Telegram's own channel search (`t.me/s/<channel>?q=keyword`) for the newest matches and then continues through older posts, keeping only posts whose text, hashtags, poll or link preview contain all the words of your query.

**Why do some videos have no `mediaUrls`?**
For larger videos Telegram's web preview shows only a thumbnail (saved in `thumbnailUrls`) and asks viewers to open the app. Media URLs are served by Telegram's CDN and may expire after some time – download files soon after scraping if you need them.

**Why is `emoji` null for some reactions?**
Those are custom (premium) emoji. They have no Unicode character, so the scraper returns their `customEmojiId` instead.

**Can I run it on a schedule?**
Yes. Use Apify Schedules with `onlyNewerThan` set to e.g. `1 day` to get only new posts every day.

**Can I use it via API or in my code?**
Yes – use the Apify API, the JavaScript/Python API clients, or integrations such as Make, Zapier, n8n, Google Sheets and webhooks.

### Is it legal to scrape Telegram?

This Actor only extracts **publicly available data** that Telegram itself publishes on the open web without login. It does not access private messages, private channels or personal account data. Still, scraped content may contain personal data or copyrighted material, so make sure your use complies with applicable laws (e.g. GDPR) and with Telegram's Terms of Service. **Do not use this tool or its data for spam, harassment or any unsolicited messaging.** If you are unsure, consult a lawyer.

### Related actors

- RSS Feed Reader & Feed Finder – RSS/Atom to JSON, Full Text
- Substack Scraper – Newsletter Posts, Full Text & Comments
- Bluesky Scraper *(coming soon)*

### Support & feedback

Found a bug or missing field? Open an issue in the **Issues** tab with the channel name. Feature requests are welcome.

# Actor input Schema

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

Public channel usernames or links. Accepted formats: <code>durov</code>, <code>@durov</code>, <code>https://t.me/durov</code>, <code>https://t.me/s/durov</code>. Private invite links (t.me/+...) and groups are not supported.

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

Maximum number of posts to scrape from each channel (newest first). Set to 0 for no limit (the whole channel history). You pay per post, so this also caps your cost.

## `onlyNewerThan` (type: `string`):

Optional. Skip posts older than this date. Use an absolute date (YYYY-MM-DD) or a relative period such as <code>7 days</code>, <code>2 weeks</code>, <code>3 months</code>. Scraping of a channel stops as soon as an older post is reached.

## `searchQuery` (type: `string`):

Optional. Only return posts that match this keyword or #hashtag, using Telegram's built-in channel search (same as t.me/s/channel?q=keyword). Applied to every channel in the list.

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

Add one extra item per channel with its title, description, subscriber count, number of photos/videos/links and avatar URL (charged as a separate 'channel-info' event).

## `includeTextHtml` (type: `boolean`):

Also save the original HTML of each post's text (formatting, links, emoji) in the <code>textHtml</code> field.

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

Usually not needed - t.me works fine without a proxy. Enable it only if you scrape a very large number of channels and start seeing HTTP 429 (rate-limit) warnings.

## Actor input object example

```json
{
  "channels": [
    "telegram",
    "durov",
    "https://t.me/bloomberg"
  ],
  "maxPostsPerChannel": 20,
  "includeChannelInfo": true,
  "includeTextHtml": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

All scraped items in the default dataset (JSON, CSV, Excel and more via the dataset export).

## `files` (type: `string`):

Records saved in the default key-value store, e.g. the run summary.

# 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",
        "durov"
    ],
    "maxPostsPerChannel": 20,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("openharvest/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",
        "durov",
    ],
    "maxPostsPerChannel": 20,
    "proxyConfiguration": { "useApifyProxy": False },
}

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

```

## MCP server setup

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