# Telegram Channel Scraper (posts, views, reactions, no login) (`scrapemole/telegram-channel-scraper`) Actor

Scrape posts from any public Telegram channel without login or API keys: text, date, views, reactions, links, photos, video, link previews and forwards, plus channel title and subscribers. Keyword search inside channels and date filters. Pay only per post delivered.

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

## Pricing

from $0.60 / 1,000 channel posts

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

## Telegram Channel Scraper: posts, views, reactions, no login

Scrape **posts from any public Telegram channel** without a Telegram account, phone number or API keys. Every row has the **post text, date, view count, reactions, links, photos, video, link preview, forwards and post URL**, plus the **channel title, description and subscriber count**. Filter by **date** or **keywords**, and export to JSON, CSV, Excel or Google Sheets, or call it from Python, n8n, Make, Zapier or an AI agent.

**You only pay per post delivered.** Private channels, groups, users, bots, invite links and channels that don't exist come back as clear error rows and are never charged.

### Why this Telegram scraper is simple and reliable

- **No login, no session files, no ban risk.** It reads Telegram's own public web preview (`t.me/s/<channel>`), the same page anyone can open in a browser. You don't need a Telegram account and nothing can get banned.
- **Pages back through the whole history**, newest first, until your post limit or date limit. In our tests: 300 of 300 posts from one channel in 11 seconds.
- **Keyword filtering across the full history**, charged only for matching posts. Telegram's own in-channel search only covers a recent window; the **Keywords** option scans as deep as you let it (default 3,000 posts per channel) and you pay only for the posts that match.
- **Date filter that stops early.** "Only posts newer than 7 days" (or a date) stops paging at the first older post, so you don't pay for or wait on old history.
- **Rich, clean fields:** view counts as numbers ("10.4M" becomes 10400000), reactions with counts (including Telegram Stars and custom emoji), photo URLs, video flags and duration, link previews, forwarded-from, reply-to, hashtags, and the edited flag.
- **Clear errors**, never silent empty runs: `NOT_FOUND` (not a public channel), `NO_DATA` (no posts in the chosen period / no keyword matches), `INVALID_INPUT`.

**Live tests, 19 Oct 2026** (real Telegram, cloud server, **no proxy**): see [Test results](#test-results).

### What you get

| Field | Description |
|---|---|
| `postId`, `postUrl`, `date`, `isEdited` | Post ID, t.me link, ISO date-time (UTC) |
| `text`, `hashtags`, `links` | Plain text (e-mails redacted), hashtags and every outbound link |
| `views`, `viewsText` | View count as a number and as shown |
| `reactions`, `reactionsTotal` | `[{ emoji, count }]`, Telegram Stars (`isPaidStars`) and custom emoji (`customEmojiId`) |
| `photos`, `hasVideo`, `videoDurationText`, `videoThumbnailUrl`, `hasDocument`, `hasPoll`, `hasSticker`, `hasVoice` | Media |
| `linkPreview` | `{ url, siteName, title, description }` |
| `forwardedFrom`, `replyToPostId` | Where it was forwarded from, and which post it replies to |
| `channelUsername`, `channelTitle`, `channelDescription`, `channelSubscribers`, `channelIsVerified`, `channelPhotos`, `channelVideos`, `channelLinks`, `channelUrl` | Channel info on every row (free; can be turned off) |
| `matchedKeywords` | Which of your keywords matched (when using Keywords) |

### How to scrape a Telegram channel

1. Add one or more **channels**: `durov`, `@durov` or `https://t.me/durov` all work.
2. Set **Max posts per channel**, and optionally **Only posts newer than** (e.g. `7 days` or `2026-10-01`) or **Keywords**.
3. Click **Start** and download the posts as JSON, CSV or Excel, or read them through the API.

#### Input example

```json
{
  "channels": ["durov", "https://t.me/bloomberg", "@cointelegraph"],
  "maxPostsPerChannel": 200,
  "onlyPostsNewerThan": "30 days",
  "keywords": ["bitcoin", "ETF"]
}
```

#### Output example

```json
{
  "status": "ok",
  "channelUsername": "bloomberg",
  "channelTitle": "Bloomberg",
  "channelDescription": "The first word in business news.",
  "channelSubscribers": 185000,
  "channelIsVerified": true,
  "channelUrl": "https://t.me/bloomberg",
  "postId": 3225,
  "postUrl": "https://t.me/bloomberg/3225",
  "date": "2026-09-22T03:26:17+00:00",
  "isEdited": false,
  "text": "Alibaba unveils new AI chip it says is China's most powerful and targets 20 gigawatts of data center capacity by 2032. https://bloom.bg/4ydroys",
  "views": 52500,
  "viewsText": "52.5K",
  "reactions": [{ "emoji": "❤", "count": 147 }, { "emoji": "🔥", "count": 131 }, { "emoji": "👍", "count": 101 }],
  "reactionsTotal": 574,
  "hashtags": [],
  "links": ["https://bloom.bg/4ydroys"],
  "photos": ["https://cdn5.telesco.pe/file/...jpg"],
  "hasVideo": false,
  "linkPreview": null,
  "forwardedFrom": null,
  "replyToPostId": null
}
```

### Pricing

Pay per post. Proxy and platform costs are included, with no start fee. Pages read while looking for keyword matches are free.

| Apify plan | Price per post | 1,000 posts |
|---|---|---|
| Free | $0.0015 | $1.50 |
| Starter (Bronze) | $0.001 | $1.00 |
| Scale (Silver) | $0.0008 | $0.80 |
| Business (Gold) | $0.0006 | $0.60 |

Set **Max cost per run** and the Actor stops cleanly when it reaches it.

### Use cases

- **Crypto and trading signals:** monitor project announcement channels, whale alerts and news channels; feed posts to your bot or LLM.
- **News and media monitoring:** track what news outlets and official channels publish, with views and reactions as reach signals.
- **Brand and competitor monitoring:** keyword alerts across many channels (schedule it hourly or daily with a date filter).
- **Research and OSINT on public channels:** archive public posts with dates, links and engagement.
- **AI datasets and RAG:** clean channel text with metadata.

### API, Python and AI agents

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("scrapemole/telegram-channel-scraper").call(run_input={
    "channels": ["durov", "telegram"], "maxPostsPerChannel": 50, "onlyPostsNewerThan": "7 days"
})
for p in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(p.get("date"), p.get("views"), (p.get("text") or p.get("errorMessage") or "")[:120])
```

Works with n8n, Make, Zapier, LangChain and the Apify MCP server, so AI agents can read Telegram channels on their own.

### Test results

Live tests on 2026-10-19 against real Telegram from a cloud server with **no proxy**: 9 runs over 8 public channels (news, crypto, tech and official Telegram channels), with date, keyword and in-channel search options.

| Metric | Result |
|---|---|
| Runs finished OK | **9/9** |
| Posts delivered | 925 |
| Duplicate posts | **0** |
| Posts older than the date filter | **0** |
| Posts with date and views | 100% |
| Billing | Charged exactly once per post delivered |
| Edge cases | bot, non-existent channel, invite link and too-short name (not charged), empty input, budget cap stops at exactly 7 of 100: **all pass** |
| Resume after a mid-history outage (mock test: page 2 down for the whole first pass) | resumed, 35/35 posts, 0 duplicates, charged 35 |
| Blocks | 0 |

### FAQ

**Which channels work?** Public broadcast channels with the web preview enabled (almost all public channels). Private channels, invite links (`t.me/+...`), groups, users and bots don't have a public preview and return `NOT_FOUND` / `INVALID_INPUT`, not charged.

**Can it scrape group chats or members?** No. It only reads public channel posts, never members, phone numbers or private chats.

**Who wrote a post?** Channel posts are published by the channel, so you get the channel name. Admin signatures are not collected.

**What's the difference between "Search inside channels" and "Keywords"?** *Search inside channels* uses Telegram's own search: fast, but it only covers a recent window. *Keywords* pages through the full history (up to *Max posts to scan*) and keeps posts containing any of your words. You pay only for matches either way.

**Can I download videos and files?** You get photo URLs, video thumbnails and flags. Full video and file downloads aren't included.

**Is it legal?** The Actor only reads content that Telegram publishes openly on the web for public channels. Respect Telegram's terms, copyright and applicable law when you reuse it.

**Found a problem?** Open an issue with the run link. Each run stores a `RUN_SUMMARY` (requests, retries, errors) to help debug it.

### More from ScrapeMole

ScrapeMole builds focused, reliable scrapers for public data: pay per result, no start fees, clear error rows that are never charged, and a `RUN_SUMMARY` on every run.

- [YouTube Transcript Scraper](https://apify.com/scrapemole/youtube-transcript-scraper)
- [Google Trends Scraper](https://apify.com/scrapemole/google-trends-scraper)
- [YouTube Scraper](https://apify.com/scrapemole/youtube-video-channel-scraper)
- [YouTube Comments Scraper](https://apify.com/scrapemole/youtube-comments-scraper)
- [Amazon Product Scraper](https://apify.com/scrapemole/amazon-product-scraper)

Website and docs: [scrapemole.pages.dev](https://scrapemole.pages.dev). Questions or a missing field? Open an issue on this Actor.

# Actor input Schema

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

Public Telegram channels: username (durov), @username, or a t.me link (https://t.me/durov). Only public broadcast channels with web preview work; private invite links (t.me/+...), groups, users and bots are reported as errors and never charged.

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

Same as Channels, in URL-list form. Handy for pasting from a spreadsheet.

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

Newest posts first. The Actor pages back through the channel history until this many posts (or the date limit) is reached.

## `onlyPostsNewerThan` (type: `string`):

Optional. A date (2026-10-01), a date-time, or a period like "7 days", "24 hours", "2 weeks". Paging stops at the first older post.

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

Optional. Uses Telegram's own in-channel search. Fast, but Telegram only searches a limited recent window of the channel. For deep history, use Keywords instead.

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

Optional. Keep only posts whose text, link preview or hashtags contain ANY of these words (case-insensitive). The Actor pages through the channel history and you pay only for matching posts. Bounded by 'Max posts to scan'.

## `maxPostsToScan` (type: `integer`):

Safety limit for keyword filtering: how many posts per channel to read while looking for matches. Not charged; only matching posts are.

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

Adds channel title, description, subscriber count and verification to each row (free).

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

How many channels to scrape at once.

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

Apify Proxy (automatic, datacenter) is enough for Telegram. The Actor rotates IPs on rate limits.

## Actor input object example

```json
{
  "channels": [
    "durov",
    "telegram"
  ],
  "maxPostsPerChannel": 50,
  "maxPostsToScan": 3000,
  "includeChannelInfo": true,
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

All dataset rows (status ok or error).

## `runSummary` (type: `string`):

JSON summary: processed/ok/failed counts, error codes, events charged, HTTP stats.

# 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": [
        "durov",
        "telegram"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

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

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

```

## MCP server setup

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