# Telegram Keyword Search Scraper - Posts by Keyword, No Login (`benthepythondev/telegram-keyword-search-scraper`) Actor

Finds public Telegram posts that mention your keywords: channels about each keyword are found for you, then Telegram's own search runs inside each. One row per post with text, date, views, reactions, media and links, plus channel subscribers, reach and a fake-subscriber hint. No account or API key.

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

## Pricing

from $2.00 / 1,000 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 Keyword Search Scraper: Posts by Keyword, No Login

Find what public Telegram channels say about a keyword, a brand or a product. Give it words; it finds public channels about each word and runs Telegram's own search inside every one of them. You get one row per matching post with its text, date, views, reactions, media and links, plus the channel's subscribers, average post reach and a hint when the subscribers look bought. No Telegram account, no API key, no phone number. Export to JSON/CSV/Excel, run on a schedule, call via API, or connect to Make, Zapier or n8n.

**Price:** pay per post saved. Until 9 November 2026 a post costs $0.0025; from 10 November the Actor is free while the new price is announced; then $0.0015 per post on the Free plan, $0.00135 Bronze, $0.00128 Silver and $0.0012 from Gold up. A post found by two keywords is charged once. Channels without results, channels without a public preview and errors cost nothing.

### 🔎 What is the Telegram Keyword Search Scraper?

Telegram has no public search across channels for people without an account, and the app's global search shows only a handful of channels. This Actor does it in two steps:

1. **Find channels.** For each keyword it reads TGStat's public channel directory (tgstat.com), which lists Telegram channels by topic. A visitor gets the first 30 channels per sort order, and seven orders (subscribers, reach, engagement, growth today, yesterday, this week, this month) give up to about 130 different channels per keyword.
2. **Search inside them.** Each channel is searched with the search box Telegram itself puts on a channel's public web preview (`t.me/s/<channel>?q=<keyword>`). The matching is Telegram's, so word forms and other languages behave as they do in the app.

You can add your own channels, turn discovery off to search only those, filter by date and skip small channels.

#### What data does it extract?

- **The post:** text with line breaks, date, link, edited flag, views, every reaction with its count, author signature
- **Media:** photo links, video links and length, media types (photo, video, document, voice, poll, sticker)
- **Links:** links in the text, link preview title and description, hashtags and @mentions
- **Context:** forwarded from (name and link), reply-to link
- **Channel:** name, title, subscribers (from Telegram), description
- **Directory stats (TGStat):** subscribers, average views of one post, citation index, topic, and **reach ratio** (average reach divided by subscribers)
- **Which keyword** found the post and **how** the channel was found

### How it compares

What users of keyword search Actors on Telegram run into, and what this one does:

| What you run into elsewhere | This Actor |
|---|---|
| Results come from a web search engine's index, so only pages Google happened to crawl appear, one post per page | Telegram's own search inside each channel: the newest matches, about 22 per channel and keyword |
| Channel discovery charged as a separate event on top of each message | Discovery is free; you pay per post saved |
| A big channel with bought subscribers looks as important as a real one | `tgstat_reach_ratio` shows it: 998,656 subscribers with 111 views per post gives 0.0001 |
| No way to add the channels you already know | `channels` adds them to every keyword, or alone with discovery off |
| Reruns return the same old posts | `postedAfter` keeps a scheduled run to new posts |

### ⬇️ Input

| Field | Type | Default | What it does |
|---|---|---|---|
| `keywords` | array | sample `bitcoin` | Words to find, one per line. Each gets its own channel search. |
| `channels` | array | none | Public channel names, @handles or t.me links to search for every keyword too. |
| `discoverChannels` | boolean | `true` | Find channels in TGStat's directory. Off: only `channels` are searched. |
| `maxChannelsPerKeyword` | integer | 30 | Found channels to search per keyword (up to 200; about 130 can be found). |
| `maxPostsPerChannel` | integer | 20 | Matching posts per channel, newest first. |
| `maxResults` | integer | 50 | Posts in total; the run stops there. |
| `postedAfter` | date | none | Only posts from this UTC date on. |
| `minSubscribers` | integer | none | Skip found channels with fewer subscribers (your own channels are always searched). |

#### Example input

```json
{
  "keywords": ["chatgpt", "openai"],
  "maxChannelsPerKeyword": 100,
  "maxPostsPerChannel": 20,
  "maxResults": 2000,
  "postedAfter": "2026-10-01",
  "minSubscribers": 5000
}
```

### ⬆️ Output

```json
{
  "keyword": "bitcoin",
  "id": "crypto_traders_altcoins/9828",
  "message_id": 9828,
  "url": "https://t.me/crypto_traders_altcoins/9828",
  "channel": "crypto_traders_altcoins",
  "text": "Michael Saylor's company, MSTR, achieved a remarkable 77.4% gain ...",
  "posted_at": "2026-10-25T19:00:09+00:00",
  "edited": true,
  "views": 25000,
  "reactions": [{"emoji": "🔥", "count": 222}, {"emoji": "❤", "count": 75}],
  "reactions_total": 370,
  "author": null,
  "forwarded_from": null,
  "media_types": [],
  "photo_urls": [],
  "video_urls": [],
  "links": ["http://rainbet.com/"],
  "hashtags": [],
  "mentions": [],
  "channel_title": "Crypto Traders — Altcoins | Bitcoin | Cryptocurrency",
  "channel_subscribers": 293000,
  "discovered_by": "tgstat:participants",
  "tgstat_category": "Cryptocurrencies",
  "tgstat_subscribers": 293308,
  "tgstat_avg_post_reach": 29200,
  "tgstat_citation_index": 0.0,
  "tgstat_reach_ratio": 0.0996,
  "scraped_at": "2026-10-26T10:02:11.418Z"
}
```

A run summary (keywords, channels searched, channels without a preview, posts saved, why it stopped) is stored as `SUMMARY` in the run's key-value store.

**Speed (measured from a server, not yet on Apify):** 40 posts in 6 s; 825 posts for two keywords over 120 channels in 23 s.

### 💡 Use cases

- 📣 **Brand monitoring:** a daily scheduled run with `postedAfter` set to yesterday shows every new post that names your brand or product.
- 🪙 **Crypto and finance research:** what channels say about a token, an exchange or a stock, with views and reactions per post.
- 🕵️ **Influencer and channel vetting:** the reach ratio and citation index separate channels with an audience from channels with bought subscribers.
- 🧠 **Datasets for AI and analysis:** post text with dates and engagement for sentiment, topic or trend analysis.

### 🤖 For AI agents

One input to copy:

```json
{"keywords": ["your brand"], "maxResults": 100}
```

All inputs are optional; no credential is needed. Rows have the same fields every time; `keyword` says which word found the post.

### Limits

- **About 22 posts per channel and keyword.** That is what Telegram's preview search shows a visitor (the newest matches). More posts come from more channels or more keywords, not from deeper paging.
- **About 130 channels per keyword.** TGStat shows a visitor the first page of each sort order; further pages need a TGStat account and are not read. Add channels you know through `channels`.
- **Public channels only.** Groups, private channels and channels that turned off their web preview cannot be searched; they are counted in the summary and not charged.
- **Counts are rounded by Telegram** (25K views). TGStat's numbers come from TGStat and can differ a little from Telegram's own count.
- Discovery uses TGStat's directory, which covers many languages but not every channel.

### ❓ FAQ

**Do I need a Telegram account or API key?** No. Everything is read from public web pages: Telegram's channel previews and TGStat's directory.

**How is a post matched?** By Telegram's own channel search, the same one the app uses. A few results match a related word form rather than the exact word.

**Why fewer posts than I asked for?** Telegram shows about 22 matches per channel, and some channels have none. The status message and the `SUMMARY` record say how many channels were searched.

**Can I search only my own list of channels?** Yes: put them into `channels` and set `discoverChannels` to false.

**Can I run it every day?** Yes. Schedule it and set `postedAfter` to a recent date so each run pays only for new posts.

**What does `tgstat_reach_ratio` mean?** Average views of one post divided by subscribers. Healthy channels are often around 0.05 to 0.5; a value near 0 with many subscribers hints at bought subscribers.

**Is a post charged twice when two keywords find it?** No. It is saved and charged once, with the first keyword that found it.

**What happens when the run is stopped or moved?** Progress is saved; a resumed run skips the channels it finished and the posts already in the dataset.

**Is it legal?** It reads public posts that channel owners publish for anyone to see. You are responsible for how you use them: respect GDPR and other privacy laws when posts contain personal data, and do not use them for spam (CAN-SPAM).

### 🔗 You might also like

- [Telegram Channel Scraper](https://apify.com/benthepythondev/telegram-channel-scraper): the whole history of channels you name, back to the first post
- [Reddit Search Scraper](https://apify.com/benthepythondev/reddit-search-scraper): keyword search across Reddit
- [Threads Search and Profile Scraper](https://apify.com/benthepythondev/threads-public-scraper): public Threads posts

**Keywords:** telegram keyword search, telegram search scraper, search telegram channels, telegram post scraper, telegram brand monitoring, telegram mentions, telegram channel finder, tgstat channels, telegram crypto signals, telegram messages export, telegram scraper no login, telegram api alternative, telegram data, telegram monitoring, telegram csv export, telegram osint

# Actor input Schema

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

Words or brand names to find in public Telegram channels, one per line. Each keyword gets its own channel search and Telegram's own search inside every channel found. An empty input searches the sample keyword.

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

Optional. Public channel names, @handles or t.me links to search for every keyword, in addition to the channels found. With channel discovery off, only these are searched.

## `discoverChannels` (type: `boolean`):

Find public channels about each keyword in TGStat's channel directory (up to about 130 per keyword). Turn it off to search only the channels you list.

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

How many found channels to search for each keyword, largest first. About 130 different channels can be found per keyword.

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

Matching posts to save from each channel, newest first. Telegram shows a visitor about the 22 newest matches per channel and keyword.

## `maxResults` (type: `integer`):

The run stops after this many posts across all keywords and channels. Each post is charged once, even when several keywords match it.

## `postedAfter` (type: `string`):

Only posts from this UTC date on (YYYY-MM-DD). Useful for a daily or weekly scheduled search.

## `minSubscribers` (type: `integer`):

Optional. Skip found channels with fewer subscribers (as counted by TGStat). Channels you list are always searched.

## Actor input object example

```json
{
  "keywords": [
    "bitcoin"
  ],
  "discoverChannels": true,
  "maxChannelsPerKeyword": 30,
  "maxPostsPerChannel": 20,
  "maxResults": 50
}
```

# Actor output Schema

## `results` (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 = {
    "keywords": [
        "bitcoin"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("benthepythondev/telegram-keyword-search-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 = { "keywords": ["bitcoin"] }

# Run the Actor and wait for it to finish
run = client.actor("benthepythondev/telegram-keyword-search-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 '{
  "keywords": [
    "bitcoin"
  ]
}' |
apify call benthepythondev/telegram-keyword-search-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,benthepythondev/telegram-keyword-search-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/Mpx3w6kHZthRnLNHQ/builds/mVUQlVzKcNvACS8UH/openapi.json
