# Telegram Channel Scraper — messages, views & media (no login) (`istmobot/telegram-channel-scraper`) Actor

Telegram scraper for public channels, no login or API key: export Telegram messages with text, views, reactions, photos, videos, links, hashtags, forwards and replies, plus subscriber counts. Search inside channels, filter by date. Telegram API alternative. Export JSON, CSV, Excel.

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

## Pricing

Pay per event

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 — export Telegram messages, views & media (no login)

Scrape **public Telegram channels** with no login, no phone number and no API key: message text, **view counts**, reactions, photos, videos, documents, polls, link previews, hashtags, forwards and replies, plus channel **subscriber counts**. Use it as a simple **Telegram API alternative** to **export Telegram messages** to JSON, CSV or Excel.

### What is Telegram Channel Scraper?

Telegram Channel Scraper is a **Telegram scraper** that reads the public web preview Telegram itself publishes for every public channel at `https://t.me/s/<channel>`, the page you see when you open a channel link in a browser. It turns that page into clean, structured data, one item per message.

- **No login, no API key, no phone number.** It never connects to the Telegram API and never signs in.
- **Public channels only.** Private chats, groups, invite links and user accounts are out of scope by design.
- **Any number of channels** in one run: usernames, `@handles` or `t.me` links.
- **Goes back in history.** It pages through older posts automatically until it has as many messages as you asked for, or until it reaches your `since` date.
- **Search inside channels** with Telegram's own channel search.
- **Polite by design.** At most 3 channels at a time, about one request per second overall, and automatic retry with backoff on HTTP 429 and server errors.
- Download your data as **JSON, CSV, Excel, HTML** or XML, or read it through the Apify API.

#### What data can I extract from Telegram channels?

| Field | Description |
|---|---|
| `channel` / `channelTitle` | Channel username and display name |
| `messageId` / `url` | Post ID and permalink (`https://t.me/<channel>/<id>`) |
| `date` | Publish time (ISO 8601, UTC) |
| `text` | Message text as plain text (line breaks kept, emoji included) |
| `textHtml` | Original message HTML (optional, `includeTextHtml`) |
| `views` | View count as a number (`18.9M` becomes `18900000`) |
| `reactions` | `[{ emoji, count }]`. Paid star reactions have `paid: true`. Custom (premium) emoji come with `customEmojiId` and `emoji: null` |
| `forwardedFrom` | `{ name, url }` of the original source when the post is a forward |
| `replyTo` | `{ messageId, url, author, text }` when the post replies to another post |
| `hasMedia` / `media` | Photos, videos (file URL, thumbnail, duration), documents (title, size), polls (question, options, %) and link previews (url, title, description, thumbnail) |
| `links` | All links in the message text |
| `hashtags` / `cashtags` | `#hashtags` and `$TICKERS` found in the text |
| `edited` | Whether the post was edited |
| `scrapedAt` | When the item was scraped |

**Channel info.** With `includeChannelInfo` on (the default), every channel also gets **one separate item with `type: "channel"`**, placed before its messages. It contains `title`, `description`, `verified`, `subscribers`, `photos`, `videos`, `files`, `links` and `avatar`. Message items have `type: "message"`, so you can split the two with a filter.

### How can I use Telegram channel data?

- **Brand monitoring.** Track what news, crypto and community channels say about your brand or product.
- **Crypto and news signals.** Pull the latest posts from crypto and breaking-news channels, together with `$TICKER` cashtags, views and reactions, and feed them into trading or alerting pipelines.
- **Market research.** Compare channels by subscribers, posting frequency, views per post and engagement.
- **OSINT on public channels.** Archive and analyse public posts for journalism and research.
- **Content archiving.** Back up a channel's public history with text, links and media URLs.
- **AI and LLM pipelines.** Feed clean channel text to summarizers, classifiers or RAG systems.

### How to scrape Telegram channels

1. Click **Try for free** on this Actor's page (you need a free Apify account).
2. Add one or more **channels**: `durov`, `@telegram` or `https://t.me/cointelegraph`.
3. Set **Max messages per channel**, and optionally a **since** date or a **search** keyword.
4. Click **Start** and wait for the run to finish.
5. Download the dataset as JSON, CSV, Excel or HTML, or connect it to your tools through the API.

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

This Actor uses **pay-per-event** pricing, so you only pay for messages you actually get:

| Event | Price |
|---|---|
| Actor start | $0.005 per run |
| `message-result` (one message in the dataset) | $0.001 per message, i.e. **$1 per 1,000 messages** |

**Channel info items and error items are never charged.**

Example: 1 run × 1,000 messages = $0.005 + $1.00 = **$1.005**.

The Apify free plan includes **$5 of monthly credit**, which covers roughly **5,000 Telegram messages** per month. You can also set a **maximum cost per run**. When the Actor reaches it, it stops cleanly and keeps everything scraped so far.

### ⬇️ Input

| Field | Type | Default | Description |
|---|---|---|---|
| `channels` | list of strings | — | Public channels as usernames, `@handles` or `t.me` URLs (required) |
| `maxMessagesPerChannel` | integer | `50` | Newest messages first. Older pages load automatically (about 20 messages per page) |
| `since` | string | — | Only messages on or after this date, e.g. `2026-01-31` |
| `searchQuery` | string | — | Keyword search inside each channel (Telegram's own search) |
| `includeChannelInfo` | boolean | `true` | Add one free `type: "channel"` item per channel |
| `includeTextHtml` | boolean | `false` | Add the original message HTML as `textHtml` |

```json
{
  "channels": ["durov", "@telegram", "https://t.me/cointelegraph"],
  "maxMessagesPerChannel": 100,
  "since": "2026-09-01",
  "includeChannelInfo": true
}
```

Search a channel for a keyword: `{ "channels": ["durov"], "searchQuery": "freedom" }`

### ⬆️ Output

One item per message, newest first, preceded by one channel item per channel. The **Overview** table in Apify Console shows channel, type, date, text, views, reactions and URL at a glance.

Message item (real output, media URLs shortened):

```json
{
  "type": "message",
  "channel": "durov",
  "channelTitle": "Pavel Durov",
  "messageId": 546,
  "url": "https://t.me/durov/546",
  "date": "2026-08-31T16:30:15.000Z",
  "text": "🏳️ Gram Wallet in Telegram is ready and is now accessible to a select group of users.\n\n🤩 We'll be gradually rolling it out to our billion+ users over the next couple of weeks.\n\n...",
  "views": 3260000,
  "reactions": [
    { "emoji": "⭐", "paid": true, "count": 35600 },
    { "emoji": null, "customEmojiId": "5399847211989246390", "count": 26900 },
    { "emoji": null, "customEmojiId": "5373223594484587136", "count": 8760 }
  ],
  "forwardedFrom": null,
  "replyTo": null,
  "hasMedia": true,
  "media": [
    {
      "type": "video",
      "url": "https://cdn4.telesco.pe/file/e0b2769474.mp4?token=...",
      "thumbnail": "https://cdn4.telesco.pe/file/s08k3hBvfTPqk3MEOz4w-....jpg",
      "duration": "0:20"
    }
  ],
  "links": [],
  "hashtags": [],
  "cashtags": [],
  "edited": false,
  "scrapedAt": "2026-10-05T02:31:25.938Z"
}
```

Channel item (real output):

```json
{
  "type": "channel",
  "channel": "cointelegraph",
  "url": "https://t.me/cointelegraph",
  "title": "Cointelegraph",
  "description": "The Future of Money \n\nUnbiased crypto, markets & Web3 news in real-time. Trusted since 2013. ...",
  "verified": false,
  "subscribers": 332000,
  "photos": 20600,
  "videos": 1290,
  "files": 4,
  "links": 58200,
  "avatar": "https://cdn4.telesco.pe/file/jPFyFIOer2JR1IPIGSeTo2wXFb3HA6XDHPrr6gSRBQc1H....jpg",
  "scrapedAt": "2026-10-05T02:30:43.651Z"
}
```

Notes on fields:

- Telegram shows rounded counts (`10.5M`, `9.69K`), so `views` and `subscribers` are rounded the same way.
- Media URLs on `telesco.pe` are signed by Telegram and **expire after a while**. Download the files soon after the run if you need to keep them.
- Telegram's web preview does not include custom (premium) emoji characters, so those reactions only carry `customEmojiId`.
- Service posts ("channel created", "pinned a message") are skipped.

#### Error items

```json
{ "channel": "wallstreetbets", "url": "https://t.me/wallstreetbets", "errorType": "GROUP_NOT_SUPPORTED", "error": "\"wallstreetbets\" is a group, not a channel — groups have no public web preview" }
```

`errorType` is one of:

- `NOT_FOUND`: no public channel with that name.
- `PREVIEW_DISABLED`: the channel exists, but its owner turned off the web preview.
- `GROUP_NOT_SUPPORTED`: the name belongs to a group.
- `NOT_A_CHANNEL`: the name belongs to a bot or user.
- `INVALID_CHANNEL`: an invite link or other unusable input.
- `FETCH_FAILED`: the page could not be loaded.

**Error items are never charged.**

### Integrations and API

**Apify API**: start a run and get the results over HTTP.

```bash
curl -X POST "https://api.apify.com/v2/acts/istmobot~telegram-channel-scraper/run-sync-get-dataset-items?token=<YOUR_API_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"channels": ["durov"], "maxMessagesPerChannel": 20}'
```

**Python** (`pip install apify-client`):

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("istmobot/telegram-channel-scraper").call(run_input={
    "channels": ["durov", "cointelegraph"],
    "maxMessagesPerChannel": 100,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    if item.get("type") == "message":
        print(item["date"], item["views"], item["text"][:80])
```

**Node.js** (`npm install apify-client`):

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('istmobot/telegram-channel-scraper').call({
    channels: ['@telegram'],
    maxMessagesPerChannel: 50,
    since: '2026-09-01',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.filter((i) => i.type === 'message'));
```

- **Schedules**: run it hourly or daily to monitor channels for new posts.
- **Webhooks**: get notified, or trigger your own pipeline, when a run finishes.
- **Make, Zapier, n8n**: send Telegram posts to Google Sheets, Airtable, Slack or a database without code.
- **AI agents**: use it from Claude, ChatGPT or any MCP client through the Apify MCP server (https://mcp.apify.com).

### FAQ

**Do I need a Telegram account, phone number or API key?** No. The Actor only reads the public `t.me/s/` web preview that anyone can open in a browser. It never logs in and never uses the Telegram API (no `api_id`, no session files).

**Which channels can I scrape?** Only **public channels** that have a username and whose web preview is enabled (most do). Private channels, groups, invite links (`t.me/+…`), bots and user accounts are not supported. You get a free error item explaining why.

**Is it legal to scrape Telegram?** The Actor collects only data that channel owners chose to publish openly on the web. Public data is generally fine to collect, but posts may contain personal data, especially names and opinions. If you store or process it, keep GDPR and similar privacy laws in mind and have a legitimate purpose. You are responsible for using the data in line with applicable laws and Telegram's terms. If unsure, consult a lawyer.

**How far back can it go?** As far as the web preview allows, which is usually the channel's full public history. Use `maxMessagesPerChannel` and `since` to control depth and cost.

**How does search work?** `searchQuery` uses Telegram's built-in channel search (`t.me/s/<channel>?q=…`). Telegram returns only the **~20–25 most recent matches** per channel. For deeper keyword monitoring, scrape without search (optionally with `since`) and filter the `text` field yourself.

**Can I get comments or the members of a channel?** No. Comments live in linked discussion groups, and member lists need a logged-in account. Neither is part of the public web preview.

**Can I schedule it?** Yes. Use Apify Schedules (hourly, daily, weekly) together with `since` or a small `maxMessagesPerChannel` to pick up new posts.

**Do I need proxies?** No. Requests are lightweight and rate-limited.

### Other Actors you might like

- [Steam Game Intelligence](https://apify.com/istmobot/steam-game-intelligence)
- [Metacritic Scraper](https://apify.com/istmobot/metacritic-scraper)
- [Earnings Call Transcripts Scraper](https://apify.com/istmobot/earnings-call-transcripts-scraper)

### Your feedback

Found a bug or want a new field? Open an issue in the **Issues** tab of this Actor. We read every one.

### Disclaimer

This is an **unofficial** tool. It is not affiliated with, endorsed by or sponsored by Telegram.

# Actor input Schema

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

Public Telegram channels: usernames (durov), @handles (@telegram) or t.me URLs (https://t.me/cointelegraph, https://t.me/s/durov). Private chats, invite links (t.me/+…) and groups are not supported.

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

Newest messages first. The Actor pages back through older messages (about 20 per page) until it has this many.

## `since` (type: `string`):

Optional. Stop at messages older than this date, e.g. "2026-01-31" or "2026-01-31T12:00:00Z".

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

Optional keyword. Uses Telegram's own channel search, which returns only the ~20–25 most recent matches per channel.

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

Add one free item per channel (type "channel") with title, description, subscribers, photo/video/link counts and avatar.

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

Also return the original message HTML (formatting, links, custom emoji) in "textHtml".

## Actor input object example

```json
{
  "channels": [
    "durov",
    "@telegram",
    "https://t.me/cointelegraph"
  ],
  "maxMessagesPerChannel": 20,
  "includeChannelInfo": true,
  "includeTextHtml": false
}
```

# Actor output Schema

## `results` (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",
        "@telegram",
        "https://t.me/cointelegraph"
    ],
    "maxMessagesPerChannel": 20
};

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

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

```

## MCP server setup

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