# Telegram Channel Scraper - Posts, Views, No Login (`wrenfield-data/telegram-channel-scraper`) Actor

Scrape public Telegram channels without login, phone number or API keys. Get posts with text and HTML, date, views, reactions, forwards, replies, photos, video thumbnails, files and link previews, plus channel info with exact subscriber counts. Date range, keyword filter and deep history.

- **URL**: https://apify.com/wrenfield-data/telegram-channel-scraper.md
- **Developed by:** [Wrenfield Data](https://apify.com/wrenfield-data) (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.70 / 1,000 post results

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 & Media (No Login)

**Telegram Channel Scraper** extracts posts from **public Telegram channels** with no Telegram account, no phone number, no bot token and no API keys. Give it channel usernames or `t.me` links and get every post with its **text (plain + HTML)**, **date**, **views**, **reactions**, **forwarded-from**, **reply-to**, **photos**, **video thumbnails**, **file names**, **link previews**, **polls** and the **edited** flag. Add one **channel info** row per channel with the title, description, **exact subscriber count**, photo and **verified / scam / fake** flags.

It reads Telegram's own public web preview (`t.me/s/<channel>`), the page anyone can open in a browser. Pagination goes as deep as the channel history: thousands of posts per channel, filtered by **date range** or **keywords**.

💸 **$1 per 1,000 posts** with views, reactions and media, and $2 per 1,000 channel-info rows (the top Telegram channel scrapers in the Store charge a median $3.50 per 1,000). No login or phone number needed. Try it on Apify's free plan ($5 of monthly credit, no credit card).

#### Sample output

| Channel | Date | Views | Reactions | Text |
|---|---|---|---|---|
| durov | 2026-10-11 | 1,140,000 | 28,400 | ✨ Designers × AI  🆕 The mockup er… |
| durov | 2026-10-10 | 1,410,000 | 116,430 | 💸 If your wallet doesn’t look lik… |
| durov | 2026-09-11 | 3,460,000 | 78,640 | 🤝 Telegram has become the sponsor… |

<sub>Real rows from the prefilled example run (Oct 19, 2026), 5 of 22+ fields shown. Export as JSON, CSV, Excel or HTML, or read them through the API.</sub>

### What data do you get?

- 📝 **Post text** as clean plain text (emoji and line breaks kept) and as **HTML** (bold, links, custom emoji)
- 📅 **Date** (UTC), **views**, **edited** flag, author signature
- ❤️ **Reactions**: each emoji (or custom emoji ID), its count and paid Star reactions, plus a total
- 🔁 **Forwarded from** (channel name, username, original post) and **reply to** (post ID, author, quoted text)
- 🖼️ **Media**: photo URLs, albums, video and GIF thumbnails (+ video URL when shown), round videos, voice, stickers, **documents with file name and size**, locations
- 🔗 **Link previews** (site, title, description, image), links, #hashtags and @mentions in the text
- 📊 **Polls** with options and percentages
- 📣 **Channel info**: title, description, exact subscriber count, photo, verified / scam / fake labels, number of photos, videos, files and links, newest post

### Use cases

- **Media monitoring & news tracking**: follow news, crypto, finance or tech channels and pull new posts on a schedule
- **Crypto & trading signals**: collect posts from signal and announcement channels with views and reactions
- **Market and competitor research**: measure reach (views, reactions, subscribers) of channels in your niche
- **OSINT and research**: archive public channels for analysis (sentiment, topic modelling, fact-checking)
- **Lead lists of channels**: check which usernames are channels, groups, users or bots, with subscriber counts

### How to scrape a Telegram channel

1. Click **Try for free** / **Start**.
2. Enter one or more **channels**: `durov`, `@telegram`, `https://t.me/s/bbcrussian`, `https://t.me/cointelegraph`.
3. Set **Max posts per channel** and/or a **date range** (`2026-01-01` to `2026-03-31`, or `From date: 7 days`).
4. Optionally add **keywords** to keep only matching posts.
5. Run and download the data as JSON, CSV, Excel or HTML, or use the API, Make, Zapier, n8n or the Apify MCP server.

### Input example

```json
{
    "channels": ["durov", "https://t.me/s/telegram", "@cointelegraph"],
    "maxPostsPerChannel": 500,
    "dateFrom": "2026-09-01",
    "dateTo": "2026-09-30",
    "keywords": ["bitcoin", "ETF"],
    "includeChannelInfo": true
}
```

- **Max posts per channel**: newest posts first. `0` = no limit (use it with **From date**).
- **Date range**: `YYYY-MM-DD`, ISO date-time or relative (`24 hours`, `7 days`, `3 months`). For an old range the Actor jumps straight to that point in the history instead of paging through everything newer.
- **Keywords**: *Contains* mode scans the history and keeps posts containing any keyword (or all, with **Require all keywords**). *Telegram search* mode uses Telegram's own search, which matches word forms but returns only about 20 of the newest matches per keyword.
- A **post link** (`https://t.me/durov/400`) starts at that post and goes back in time.

### Output example

```json
{
    "type": "post",
    "channel": "durov",
    "channelTitle": "Pavel Durov",
    "postId": 529,
    "url": "https://t.me/durov/529",
    "date": "2026-06-16T15:05:29Z",
    "text": "🚫 India’s IT ministry banned Telegram for one week because some users shared leaked exam questions.\n\n...",
    "textHtml": "<tg-emoji emoji-id=\"5240241223632954241\">...</tg-emoji> India’s IT ministry banned Telegram ...",
    "views": 9710000,
    "viewsText": "9.71M",
    "isEdited": false,
    "author": "Pavel Durov",
    "forwardedFrom": null,
    "replyTo": null,
    "mediaType": "text",
    "media": [],
    "photoUrls": [],
    "videoThumbnailUrls": [],
    "documentNames": [],
    "linkPreview": null,
    "links": [],
    "hashtags": [],
    "mentions": [],
    "reactions": [
        { "emoji": "⭐", "customEmojiId": null, "isPaid": true, "count": 6280, "countText": "6.28K" },
        { "emoji": null, "customEmojiId": "5265077361648368841", "isPaid": false, "count": 69600, "countText": "69.6K" }
    ],
    "reactionsTotal": 120838,
    "scrapedAt": "2026-10-09T01:33:36Z"
}
```

Channel info row:

```json
{
    "type": "channel",
    "status": "ok",
    "channel": "durov",
    "url": "https://t.me/durov",
    "title": "Pavel Durov",
    "description": "Founder of Telegram.",
    "subscribers": 10464256,
    "subscribersText": "10.5M",
    "photoUrl": "https://cdn4.telesco.pe/file/...jpg",
    "isVerified": true,
    "isScam": false,
    "isFake": false,
    "photosCount": 102,
    "videosCount": 46,
    "linksCount": 200,
    "lastPostId": 548,
    "lastPostDate": "2026-09-11T16:04:02Z"
}
```

### Channels that can't be scraped (free rows)

You get one **free** row with `type: "error"` and a `status` explaining why:

| status | meaning |
|---|---|
| `no_web_preview` | The channel exists but its owner disabled the public preview (title and subscribers are still returned) |
| `private` | Invite link (`t.me/+...`, `joinchat`) or `t.me/c/...` link to a private chat |
| `not_found` | No public chat with this username (deleted, banned, private or mistyped) |
| `is_group` / `is_user` / `is_bot` | The username is a group, a person or a bot, not a channel |
| `invalid_input` | Not a valid username or t.me link |
| `no_posts` / `no_matches` | The channel has no visible posts / no posts matched your keywords |

### Pricing

This Actor uses **pay-per-event** pricing. You pay per **post** saved (`post-result`) and per **channel info** row (`channel-result`). Error rows, channels that can't be scraped, and posts removed by your date or keyword filters are **free**. Check the **Pricing** tab for current prices.

Cap your spending with the run's **maximum cost** or **maximum paid results**: the Actor stops cleanly at the limit.

### How it works

- The Actor loads Telegram's public web preview `https://t.me/s/<channel>` and pages back with `?before=<post id>`, 20 posts per page. No browser runs, so it's fast and cheap: about 1,000 posts in 10-20 seconds.
- Large channels are split into parallel page streams; date ranges use a binary search over post IDs to jump to the right point.
- Requests go **direct** first. Only if Telegram rate-limits the run does it switch to the Apify datacenter proxy (configurable).
- Exact subscriber counts come from the channel's `t.me/<channel>` page (the preview shows rounded numbers like 10.5M).
- A run summary (key-value store record `SUMMARY`) lists every channel with its status, posts and pages.

### Limitations

- Only **public channels** with the web preview enabled. Private channels, groups, comments and member lists need a logged-in Telegram account and are not supported.
- **Views and reaction counts are rounded** by Telegram on large numbers (`18.9M`, `4.71K`); the Actor converts them to numbers.
- Some post types (stories, giveaways, paid media, some audio) show "Please open Telegram to view this post" in the preview; they are returned with `mediaType: "unsupported"` and whatever metadata is visible.
- Media URLs point to Telegram's CDN and are signed: download files soon after scraping if you need them.
- Telegram search mode returns at most ~20 newest matches per keyword (Telegram's limit); use *Contains* mode for deep keyword scans.

### Related tools

Monitor the same topics on YouTube and in Google search interest.

- [YouTube Transcript Scraper](https://apify.com/wrenfield-data/youtube-transcript-scraper): transcripts and subtitles from videos, channels and searches
- [Google Trends Scraper](https://apify.com/wrenfield-data/google-trends-scraper): interest over time, by region, related queries and Trending Now

All of these are maintained by the same developer and export flat JSON, CSV or Excel, so you can feed one tool's dataset into the next.

### FAQ

**Do I need a Telegram account, phone number or API ID?** No. The Actor only reads pages that are public on the web.

**How far back can it go?** To the first post of the channel, as long as the posts are visible in the web preview.

**Can I scrape private channels or groups?** No. Only public channels expose a web preview.

**Is scraping Telegram legal?** The Actor only reads pages Telegram publishes openly on the web, without logging in. However, Telegram's [Terms of Service](https://telegram.org/tos) and its [Content Licensing and AI Scraping Terms](https://telegram.org/tos/content-licensing) restrict access to user-generated content beyond ordinary use and **explicitly forbid using Telegram data to train or develop AI / machine-learning models**. Posts are also copyrighted by their authors and can contain personal data (GDPR and similar laws apply). You are responsible for making sure your use is lawful and compatible with these terms; if in doubt, consult a lawyer. Do not use this Actor to build AI training datasets.

**Can I monitor channels for new posts?** Yes: schedule the Actor with `dateFrom: "24 hours"` (or `1 hour`) and connect the dataset to Slack, Google Sheets, a webhook or your app.

# Actor input Schema

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

Public Telegram channels, one per line: a username (<code>durov</code>, <code>@durov</code>) or a link (<code>https://t.me/durov</code>, <code>https://t.me/s/durov</code>). A post link (<code>https://t.me/durov/400</code>) starts from that post and goes back in time. Private invite links, groups, users and bots are reported as free error rows.

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

Newest posts to return per channel (after date and keyword filters). Set 0 for no limit when you use <b>From date</b>. Pagination goes as deep as the channel's history (thousands of posts are fine).

## `dateFrom` (type: `string`):

Only posts published on or after this date. <code>YYYY-MM-DD</code>, an ISO date-time (UTC), or relative: <code>7 days</code>, <code>24 hours</code>, <code>3 months</code>.

## `dateTo` (type: `string`):

Only posts published on or before this date (a plain date includes the whole day, UTC). The scraper jumps straight to that point in the channel history, so old ranges are fast.

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

Only return posts containing any of these words or phrases (case-insensitive; checked in the post text, file names, link preview and poll question). Posts that don't match are not charged. Leave empty for all posts.

## `keywordMode` (type: `string`):

<b>Contains</b> scans the channel history (respecting the date range) and keeps matching posts - exact and as deep as you need. <b>Telegram search</b> uses Telegram's own search (matches word forms) but Telegram returns only about 20 of the newest matches per keyword.

## `matchAllKeywords` (type: `boolean`):

Only keep posts that contain every keyword (default: any keyword).

## `wholeWordsOnly` (type: `boolean`):

Match keywords as whole words (<code>SEC</code> won't match "second"). Turn off to also match inside words, e.g. word forms (<code>Трамп</code> → "Трампа") or prefixes (<code>crypto</code> → "cryptocurrency"). Chinese, Japanese, Korean and Thai keywords always match anywhere.

## `maxScannedPostsPerChannel` (type: `integer`):

With a keyword filter, stop scanning a channel after this many posts even if fewer matches were found. Scanned posts that don't match are free.

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

Add one row per channel with title, description, exact subscriber count, photo, verified / scam / fake flags and media counters.

## `includeHtml` (type: `boolean`):

Add <code>textHtml</code> (formatting, links, custom emoji) next to the plain <code>text</code>.

## `includeServiceMessages` (type: `boolean`):

Include 'Channel created', 'Channel photo updated' and similar service messages.

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

Telegram's web preview usually works without a proxy. This proxy is used only if Telegram starts rate-limiting the run (then the rest of the run goes through it). The default Apify datacenter proxy is enough.

## `alwaysUseProxy` (type: `boolean`):

Send every request through the proxy above instead of connecting directly first.

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

Parallel page requests. Large single channels are split into parallel page streams.

## Actor input object example

```json
{
  "channels": [
    "durov"
  ],
  "maxPostsPerChannel": 20,
  "keywordMode": "contains",
  "matchAllKeywords": false,
  "wholeWordsOnly": true,
  "maxScannedPostsPerChannel": 5000,
  "includeChannelInfo": true,
  "includeHtml": true,
  "includeServiceMessages": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "alwaysUseProxy": false,
  "maxConcurrency": 10
}
```

# Actor output Schema

## `posts` (type: `string`):

No description

## `channels` (type: `string`):

No description

## `allRows` (type: `string`):

No description

## `summary` (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 = {
    "channels": [
        "durov"
    ],
    "maxPostsPerChannel": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

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

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

```

## MCP server setup

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