# Telegram Search Scraper (`lightmoon/telegram-search-scraper`) Actor

Search public Telegram by keyword: channels, groups, bots and individual posts, each with its t.me link, name and text. Optional channel details straight from Telegram. No account, no API key.

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

## Pricing

from $2.20 / 1,000 search matches

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

Search public Telegram by keyword and get what matches as rows you can sort:
channels, groups, bots and individual posts, each with its `t.me` link, its
name and its text. Optionally look every channel up on Telegram itself for the
exact subscriber count. No Telegram account, no API key, no phone number.

```json
{ "searchQueries": ["home coffee roasting"], "resultType": "channels", "maxResults": 100 }
```

> **Unofficial.** This Actor is not affiliated with, endorsed by or sponsored by Telegram. It reads only publicly available pages, does not log in and does not bypass any access control. All product names and trademarks belong to their respective owners.

### What one row looks like

A real row from a real run, unedited:

```json
{
  "query": "home coffee roasting",
  "rank": 3,
  "kind": "channel",
  "title": "Coffee Roasters Club",
  "url": "https://t.me/coffeeroastersclub",
  "username": "coffeeroastersclub",
  "messageId": null,
  "snippet": "Home roasting tips, bean sources and profiles for small batch roasters",
  "matchedAllWords": true,
  "language": null,
  "totalResultsForQuery": 412,
  "channelSubscribers": 18432,
  "channelIsVerified": false,
  "enriched": true,
  "scrapedAt": "2026-09-30T16:12:04+00:00"
}
```

| column | what it is |
|---|---|
| `kind` | `channel`, `group`, `bot`, `post` or `article` |
| `url` · `username` | the Telegram link and the @name behind it |
| `messageId` | for a post, the number in its own link |
| `snippet` | the description, or the matching text of a post |
| `matchedAllWords` | whether every word of your phrase is really in it |
| `totalResultsForQuery` | how many matches the search has in total |
| `channelSubscribers` | exact, read from Telegram — only with channel details on |

### The one thing worth knowing before you run it

**The search matches your words, not your phrase.** Ask for
`woodworking tools` and you will also be offered places that carry only
`tools`. That is how public Telegram search works, and nothing in its answer
says so.

So every row here carries **`matchedAllWords`** — whether all of your words
really appear in the name or the description — and the run tells you how many
of your results were full matches. Sort on that column and you have the precise
answers on top and the neighbourhood underneath, without anything thrown away.

If you would rather only pay for exact ones, turn on **Only keep results
containing every word**: the rest are dropped before they are charged for. It
is off by default because the search prints a description for about two results
in three, and for the remaining third there is only a name to read — a
multi-word phrase would drop them all whether or not they were any good.

### What you can search

- **Channels and groups** — places to follow, with names and descriptions.
- **Bots** — by what they advertise themselves as.
- **Messages** — individual posts, each with its own link and the text that
  matched. Useful for watching a topic or a brand name.
- **Telegraph articles** — pages published through Telegram's publishing tool.
  They live on `telegra.ph`, not inside Telegram.

Add a two-letter language code to narrow any of these to one language.

### Channel details

With **Look each channel up on Telegram** turned on, every channel found is
also read from Telegram's own public page: exact subscriber count, the full
description, the verified badge, the avatar.

Two honest notes about it. It costs a second request per result and is charged
at the higher rate — leave it off if you only want links. And some names
Telegram will not show a preview for at all: a group, a channel whose owner
switched the preview off, or a name that no longer exists all look identical
from outside. Those rows still come back, marked in `enrichmentNote`, and are
charged at the plain rate rather than the enriched one.

### How big is a search, really

Measured on 2026-09-30:

| phrase | matches |
|---|---|
| `bitcoin` | 199 458 |
| `bitcoin`, channels only | 3 859 |
| `woodworking`, channels only | **38** |

Broad topics are effectively bottomless; a narrow one can be a few dozen and
then genuinely finished. Every row carries `totalResultsForQuery` so you can
see which you are in, and a run that finds nothing says so plainly instead of
failing.

### Limits

- Up to **50 phrases** and **5 000 results** in one run.
- Channel lookups are capped at **500** per run.
- Results come from a public index of Telegram plus Telegram's own public
  pages. Private channels, invite-only groups and anything requiring an account
  are not visible and never will be.

### Free plan

The free trial covers **100 results**. Everything works the same on the free
plan; only the row count differs, and a run stops cleanly when its charge limit
is reached rather than failing.

# Actor input Schema

## `searchQueries` (type: `array`):

What you would type into a search box. One phrase per line: `home coffee roasting`, `crypto signals`, `python jobs`. Up to 50 phrases in one run.

## `resultType` (type: `string`):

Channels and groups are places you can follow. Messages are individual posts and come with the post's own link. Telegraph pages are articles published through Telegram's publishing tool — they are not inside Telegram itself.

## `strictMatch` (type: `boolean`):

Off by default, on purpose. The search matches your words separately, so `woodworking tools` also returns places carrying only `tools`. Turning this on keeps only results where every word of your phrase appears in the name or the description — and the ones dropped are never charged for. Leave it off for a broad sweep: the search shows a description for about two results in three, so for the rest there is only a name to judge by and a multi-word phrase would drop them all. Either way every row carries `matchedAllWords`, so you can sort on it afterwards.

## `language` (type: `string`):

A two-letter code such as `en`, `ru`, `es`. Narrows results to that language. Leave empty for all languages.

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

Across every phrase in the run. The free trial covers 100.

## `enrichChannels` (type: `boolean`):

Off by default. When on, every channel found is also read from Telegram itself for its exact subscriber count, full description, verified badge and avatar. This costs a second request per result and is charged at the higher rate — a result Telegram will not show is still returned and still charged at the plain rate.

## Actor input object example

```json
{
  "searchQueries": [
    "home coffee roasting"
  ],
  "resultType": "channels",
  "strictMatch": false,
  "maxResults": 50,
  "enrichChannels": false
}
```

# Actor output Schema

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

No description

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

No description

## `messages` (type: `string`):

No description

## `all` (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 = {
    "searchQueries": [
        "home coffee roasting"
    ],
    "resultType": "channels",
    "strictMatch": false,
    "maxResults": 50,
    "enrichChannels": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("lightmoon/telegram-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 = {
    "searchQueries": ["home coffee roasting"],
    "resultType": "channels",
    "strictMatch": False,
    "maxResults": 50,
    "enrichChannels": False,
}

# Run the Actor and wait for it to finish
run = client.actor("lightmoon/telegram-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 '{
  "searchQueries": [
    "home coffee roasting"
  ],
  "resultType": "channels",
  "strictMatch": false,
  "maxResults": 50,
  "enrichChannels": false
}' |
apify call lightmoon/telegram-search-scraper --silent --output-dataset

```

## MCP server setup

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