# Telegram Channel Search Scraper (topic, subscribers, no login) (`datahamster/telegram-channels-search`) Actor

Telegram channel search by topic keyword: every public channel as one row with subscriber count, title, description, last post and photo. Telegram groups search is included, with a member-count filter. No login, no bot token, no API key; you pay only for the rows you get.

- **URL**: https://apify.com/datahamster/telegram-channels-search.md
- **Developed by:** [Viktor Dubnytskiy](https://apify.com/datahamster) (community)
- **Categories:** Social media
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 result items

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Telegram Channel Search Scraper (topic, subscribers, no login)

Find public Telegram channels and groups by topic and get one flat row per community: subscriber count, title, description, photo, last post time and whether it is a channel or a group. No Telegram account, no phone number, no bot token, no API key — the actor reads only the public `t.me` pages Telegram serves to anyone.

### What you get

One row per channel or group: `id`/`username`, `url`, `title`, `subscribers`, `subscribersText`, `description`, `kind` (`channel` or `group`), `photoUrl`, `lastPostAt`, `verified`, `available` (always `true`: dead t.me links and unread pages are never emitted), `detailsFetched`, `query`, `rank`, `source`, `scrapedAt`.

### Example output

Real rows (query `crypto signals`, plus `@durov`):

| Field | Channel | Group |
|---|---|---|
| `url` | `https://t.me/durov` | `https://t.me/chat_crypto` |
| `title` | `Pavel Durov` | `Crypto Chat — Degen Calls` |
| `subscribers` | `10800000` (`10.8M`) | `1426` (`1 426 members, 37 online`) |
| `kind` | `channel` | `group` |
| `description` | `Founder of Telegram.` | `Crypto Chat- DEGEN community for finding alpha…` |
| `lastPostAt` | `2026-09-11T16:04:02+00:00` | – (no public preview) |
| `verified` | `true` | `false` |

### Use cases

- Build a list of the Telegram communities in one niche and sort them by size before buying a post or joining.
- Telegram groups search for a city or a language: find where a topic is actually discussed, with the member count next to each group.
- Track a set of channels and get an alert when the subscriber count, title or description changes.
- Find small communities to work with: set `maxSubscribers` and skip the crowded channels.

### How it works

1. **Discovery** — each topic is searched in a public search-engine index restricted to `t.me`, so you get the channels Telegram itself has published to the open web. Post links (`t.me/name/1234`) and preview links (`t.me/s/name`) collapse into one channel; private invite links (`t.me/+hash`, `joinchat`) and site sections are skipped.
2. **Enrichment** — every hit's public page is opened before it can become a row: the preview `t.me/s/<name>` when the channel serves one (that is where `lastPostAt` comes from), otherwise the plain `t.me/<name>` card, which is what Telegram serves for groups and for channels with previews disabled. `subscribers`/`members` from that page also decide `kind`.
3. **Filter** — `minSubscribers` / `maxSubscribers` are applied after enrichment.
4. Empty search answers are retried once; a challenge on every query is reported as a block, a genuine zero-hit answer ends as `no_matches`. An empty dataset never hides a wall, and never claims one either.

### Input

| Field | Meaning | Default |
|---|---|---|
| `queries` | Topics to search, e.g. `crypto signals`, `київ новини` | `["crypto signals"]` |
| `channelUrls` | Known t.me links or @usernames to enrich directly | empty |
| `resultsPerQuery` | Search hits scanned per topic (1-200) | `10` |
| `minSubscribers` / `maxSubscribers` | Size bounds applied after enrichment | empty |
| `maxItems` | Stop after this many rows | `20` |
| `mode` | `scrape` or `monitor` (only new/changed since last run) | `scrape` |
| `monitorKey`, `webhookUrl`, `telegramBotToken`, `telegramChatId` | Monitor-mode state key and alert targets | empty |

### Pricing

| Event | Price |
|---|---|
| result | $0.003 per channel ($3 per 1,000) |
| monitor-check | $0.006 per monitor run |
| change | $0.003 per new/changed channel |

Charged only for rows actually pushed. No proxy is needed, so platform usage stays small.

### Why this actor

- No login, no phone number, no bot token and no API key — nothing to keep alive, nothing to get banned.
- Channels and groups come out of the same run, and `kind` tells them apart.
- Size filters in the input, so you can ask for "communities between 1,000 and 20,000 members" directly.
- Monitor mode with webhook and Telegram alerts on subscriber, title and description changes.
- A run that finds nothing pushes nothing and charges no result events; the run summary explains why.

### Limits

- A search hit whose t.me page could not be read (dead link, or the page did not answer after retries) is dropped, not returned half-empty: every row comes from a page that was actually read, so the personal-account check has always run.

- Telegram has no public channel search of its own, so discovery depends on the search-engine index: channels that are never linked from the open web will be missing. Give the topic in the language the channel is written in.

- `subscribers` is the number Telegram prints on the public page; large channels show it rounded (`10.8M`), and the raw text is kept in `subscribersText`.

- `lastPostAt` exists only for channels that serve a public preview. Groups and preview-less channels return `null` there.

- While `minSubscribers` or `maxSubscribers` is set, rows whose count could not be read (a channel that is gone, or a page that did not answer) are dropped, because an unknown count cannot satisfy a bound.

- Personal Telegram accounts and bots are never returned: every candidate's `t.me` page is opened first, and a page without a subscriber or member counter is skipped, not emitted. There is no setting that turns this off. No members, no admins, no message authors.

- Message text is out of scope here — use the `telegram-public-channels` actor for posts, views and media.

### FAQ

**Does it need a Telegram account, phone number or bot token?** No. There is no credential field at all; every request is a plain public web request.

**Can it find groups, not just channels?** Yes. Public groups appear with `kind: "group"` and their member count in `subscribers`; the raw label (`1 426 members, 37 online`) stays in `subscribersText`.

**Does it return members or message authors?** No. Only channel-level facts. Personal profiles found by the search index are dropped before anything is pushed.

**What happens when there are no results?** No rows are pushed and no result events are charged. The `RUN_SUMMARY` record in the run's key-value store carries `emptyReason`, which separates "the topic has no public channels in the index" from "the search index answered with a challenge".

### Changelog

- 0.1: initial release — topic discovery, channel and group enrichment (subscribers, description, last post, photo), size filters, monitor mode; empty search results are retried and reported as a block instead of an empty dataset.

***

If this actor saved you time, a short review on its Store page genuinely helps other people find it. Found a bug or need a field that is missing? Open a ticket on the **Issues** tab.

# Actor input Schema

## `maxItems` (type: `integer`):

Stop after this many results (you are charged only for pushed items)

## `mode` (type: `string`):

scrape = full results; monitor = only new/changed items since the previous run of this task

## `monitorKey` (type: `string`):

Optional state key when not running as a saved task

## `webhookUrl` (type: `string`):

POST a change summary here in monitor mode

## `telegramBotToken` (type: `string`):

Optional: bot token for monitor-mode change summaries

## `telegramChatId` (type: `string`):

Optional: chat id that receives monitor-mode summaries

## `queries` (type: `array`):

Topics to find public Telegram channels and groups for, one per line, e.g. "crypto signals", "київ новини", "python jobs", "berlin techno". Any language works.

## `channelUrls` (type: `array`):

Known channels to enrich directly, e.g. "https://t.me/durov", "t.me/s/telegram" or "@durov". Post links such as "https://t.me/durov/351" collapse into their channel. Can be combined with Search queries or used alone.

## `resultsPerQuery` (type: `integer`):

How many search hits to scan per topic, e.g. 10. More hits mean more channels but a longer run; after de-duplication the number of channels is usually lower. Range 1-200.

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

Keep only channels and groups with at least this many subscribers/members, e.g. 5000. Channels whose count could not be read are dropped while this filter is set. Leave empty for no lower bound.

## `maxSubscribers` (type: `integer`):

Keep only channels and groups with at most this many subscribers/members, e.g. 50000 to find small niche communities. Channels whose count could not be read are dropped while this filter is set. Leave empty for no upper bound.

## Actor input object example

```json
{
  "maxItems": 20,
  "mode": "scrape",
  "queries": [
    "crypto signals"
  ],
  "resultsPerQuery": 10
}
```

# Actor output Schema

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

All pushed rows (dataset, JSON)

## `resultsTable` (type: `string`):

Dataset in the Console viewer

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

RUN\_SUMMARY record

# 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 = {
    "queries": [
        "crypto signals"
    ],
    "resultsPerQuery": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("datahamster/telegram-channels-search").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 = {
    "queries": ["crypto signals"],
    "resultsPerQuery": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("datahamster/telegram-channels-search").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 '{
  "queries": [
    "crypto signals"
  ],
  "resultsPerQuery": 10
}' |
apify call datahamster/telegram-channels-search --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datahamster/telegram-channels-search"
        }
    }
}
```

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/Nos8XhQvD7W0spXfD/builds/WjctvDAlzLBRhqjT8/openapi.json
