# Telegram Keyword Search & Alerts Scraper (`i-scraper/telegram-keyword-search`) Actor

Unofficial public-source Telegram scraper. Search posts by keyword, monitor known public channels, receive only new matches, cluster reposts, and export structured Telegram data. No Telegram account required; optional AI relevance.

- **URL**: https://apify.com/i-scraper/telegram-keyword-search.md
- **Developed by:** [i-Scraper](https://apify.com/i-scraper) (community)
- **Categories:** Social media, Lead generation, 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 telegram 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/platform/actors/running/actors-in-store#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

Search public Telegram posts by keyword, monitor selected public channels, and turn Telegram data into structured alerts — without a Telegram account or session string.

**Telegram Keyword Search & Alerts Scraper** is built for Telegram monitoring, OSINT, brand intelligence, lead discovery, market research, news tracking, and narrative analysis. It combines public web discovery with direct polling of known public channel preview pages, removes duplicate messages, groups reposts, and can return only new matches on scheduled runs.

> **Unofficial tool:** This Actor is not affiliated with, endorsed by, or sponsored by Telegram. It accesses only publicly available pages and search results.

### What can this Telegram keyword search Actor do?

- Search indexed public Telegram posts using one or more keywords.
- Monitor up to 100 known public Telegram channels by username or `t.me` link.
- Match an exact phrase, all words, any word, a safe regular expression, or a semantic intent.
- Add required terms, excluded terms, synonyms, spelling variants, and Cyrillic transliteration.
- Filter Telegram messages by channel, date, language, views, and reactions.
- Save only new or edited matches across scheduled runs with a stable monitor ID.
- Deduplicate messages found through multiple discovery paths.
- Cluster identical and near-duplicate posts while preserving every source link.
- Generate an optional digest of the most active narratives.
- Add optional OpenAI relevance scoring, evidence quotes, lead detection, sentiment, and intent matching.
- Export structured Telegram data to JSON, CSV, Excel, XML, or RSS through the Apify dataset.
- Connect results to webhooks, Zapier, Make, Google Sheets, Slack, a database, or your own API workflow.

### Popular use cases

- **Brand monitoring:** find public mentions of a company, product, executive, or campaign.
- **Lead generation:** detect messages asking for product recommendations, alternatives, vendors, or help.
- **OSINT and investigations:** collect public evidence with source URLs, timestamps, and channel metadata.
- **News and crisis monitoring:** watch known channels and discover indexed posts about a developing event.
- **Crypto and financial research:** track public narratives, token mentions, market commentary, and repost velocity.
- **Competitor intelligence:** monitor product launches, pricing discussions, customer complaints, and migrations.
- **Content research:** group repeated stories and identify which public channels are amplifying them.

### Quick start: search public Telegram posts

Enter one or more search rules and click **Start**:

```json
{
  "queries": [
    {
      "text": "CRM alternative",
      "mode": "allWords",
      "includeTerms": ["recommend"],
      "excludeTerms": ["course", "job"],
      "synonyms": ["CRM replacement"]
    }
  ],
  "languages": ["en"],
  "maxResultsPerQuery": 100,
  "clusterResults": true
}
```

The Actor searches bounded public web results for Telegram post links, verifies the matching public posts where possible, applies your filters, and saves the results to the default dataset.

### Quick start: monitor public Telegram channels

Use `knownChannels` when you already know which public channels matter. Results are limited to those channels by default. Enable `onlyNew` and keep the same `monitorId` on every scheduled run:

```json
{
  "queries": [
    {
      "text": "artificial intelligence",
      "mode": "allWords"
    }
  ],
  "knownChannels": [
    "durov",
    "https://t.me/example_public_channel"
  ],
  "onlyNew": true,
  "monitorId": "ai-news-daily",
  "generateDigest": true,
  "maxResultsPerQuery": 100
}
```

For continuous Telegram monitoring, save this input as an Apify Task and attach a schedule. The first run creates the checkpoint; later runs with the same `monitorId` skip previously delivered message versions. If a public post is edited and its text changes, the new version can be delivered again.

To combine selected-channel monitoring with global public web discovery, set `searchGlobalWeb` to `true`. Selected channels are processed first, so global matches cannot consume their result quota before they are evaluated.

### Search modes

| Mode | Best for | Example |
|---|---|---|
| `exact` | A phrase in the same word order | `"funding round"` |
| `allWords` | All keywords in any order | `CRM alternative` |
| `anyWords` | Broad discovery | `outage downtime incident` |
| `regex` | Controlled text patterns | `Series\\s+[A-E]` |
| `semanticIntent` | Retrieval plus optional AI intent scoring | `companies looking to replace their CRM` |

Deterministic matching is always applied before results are stored. AI is optional and does not replace the original public message text or source URL.

### Input parameters

| Field | Type | Description |
|---|---|---|
| `queries` | array | Up to 20 keyword rules with match mode, include/exclude terms, synonyms, and transliteration. |
| `intent` | string | Natural-language monitoring goal used for semantic retrieval and AI relevance. |
| `knownChannels` | array | Up to 100 public usernames or `t.me` links. When present, search is limited to these channels by default. |
| `searchGlobalWeb` | boolean | Also run global public web discovery when `knownChannels` is present. Global discovery runs automatically when no channels are supplied. |
| `includeChannels` | array | Optional allowlist of public channels. |
| `excludeChannels` | array | Public channels to ignore. |
| `fromDate`, `toDate` | date | UTC publication-date filters. |
| `languages` | array | ISO language codes such as `en`, `es`, or `ru`. |
| `minViews` | integer | Minimum known view count. Posts without a visible count remain eligible. |
| `minReactions` | integer | Minimum known reaction count. Posts without visible reaction data remain eligible. |
| `maxResultsPerQuery` | integer | Maximum retained matches per original query; default is 100. |
| `onlyNew` | boolean | Return only message versions not delivered by the same monitor before. |
| `monitorId` | string | Stable checkpoint name; required when `onlyNew` is enabled. |
| `webSearchProvider` | string | `auto`, `duckduckgo`, or `bing`; automatic mode can fall back between providers. |
| `clusterResults` | boolean | Group exact and near-duplicate messages; enabled by default. |
| `generateDigest` | boolean | Add a compact digest record for the largest clusters. |
| `proxyConfiguration` | object | Optional Apify Proxy configuration for public HTTP requests. |

At least one query, monitoring intent, or known public channel is required.

### Optional AI relevance and lead detection

Set `aiMode` to `openai` to enrich deterministic matches. Your OpenAI API key is accepted as a secret input and is used only for the OpenAI requests made by this Actor.

```json
{
  "queries": [
    {
      "text": "CRM",
      "mode": "anyWords"
    }
  ],
  "intent": "Find companies actively asking for a CRM replacement",
  "aiMode": "openai",
  "openaiApiKey": "YOUR_OPENAI_API_KEY",
  "openaiModel": "gpt-4.1-mini",
  "alertMode": "relevantOnly",
  "relevanceThreshold": 75,
  "maxAiItems": 100,
  "aiBudgetUsd": 1
}
```

AI output can include `relevanceScore`, `matchedIntent`, `relevanceReason`, `evidenceQuote`, `isActionableLead`, and `sentiment`. Evidence quotes are accepted only when they occur verbatim in the original message. The `maxAiItems` and `aiBudgetUsd` settings bound the amount of AI enrichment attempted during a run. OpenAI API usage is billed separately by OpenAI to the supplied key.

### Telegram data output

Each message is stored as a flat, API-ready dataset record:

```json
{
  "recordType": "message",
  "monitorId": "crm-leads-hourly",
  "discoverySource": "public_preview",
  "coverage": "recent_public_channel_preview",
  "matchedQuery": "CRM alternative",
  "channelUsername": "example_public_channel",
  "channelTitle": "Example Public Channel",
  "channelUrl": "https://t.me/example_public_channel",
  "messageId": 1842,
  "messageUrl": "https://t.me/example_public_channel/1842",
  "publishedAt": "2026-08-10T09:15:00+00:00",
  "text": "Can anyone recommend a CRM alternative for a small support team?",
  "language": "en",
  "views": 12400,
  "forwards": 37,
  "reactions": 86,
  "mediaType": null,
  "isNew": true,
  "relevanceScore": 94,
  "evidenceQuote": "recommend a CRM alternative",
  "isActionableLead": true,
  "clusterId": "cluster-9a2b...",
  "retrievedAt": "2026-08-10T09:20:00+00:00"
}
```

The dataset may also contain:

- `cluster` records summarizing a group of at least two related or reposted messages;
- one `digest` record when `generateDigest` is enabled;

Unique messages do not create single-message clusters and keep `clusterId: null`. The `recordType` field makes message, cluster, and digest records easy to separate in downstream workflows.

Run-level metadata is stored separately in the default Key-Value Store under `OUTPUT`. It includes coverage, request counts, duplicate counts, AI usage, checkpoint status, and incomplete-provider details without adding a technical row to the message dataset.

### Run with the Apify API

Start the Telegram scraper from any application with the Apify API:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/i-scraper~telegram-keyword-search/runs?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "queries": [{"text": "product launch", "mode": "allWords"}],
    "knownChannels": ["example_public_channel"],
    "maxResultsPerQuery": 50
  }'
```

After the run finishes, read the default dataset through the API or export it from the **Output** tab. You can also use the official Apify API clients for JavaScript and Python.

### Automate Telegram alerts

For a recurring alert workflow:

1. Create an Apify Task with your queries, `knownChannels`, `onlyNew: true`, and a stable `monitorId`.
2. Schedule the Task hourly, daily, or at another interval.
3. Add a webhook or integration that runs after a successful Actor run.
4. Forward message records to Slack, email, Google Sheets, a CRM, a database, or your own endpoint.

Use a different `monitorId` for each logically separate watchlist. Reusing one monitor ID intentionally shares its delivered-message checkpoint.

### Pricing and cost control

This Actor uses transparent pay-per-event pricing. You pay a small run-start fee plus one `telegram-result` event for every matching Telegram post saved to the dataset. Cluster, digest, and run-summary records are not charged as results.

| Event | Free | Bronze | Silver | Gold |
|---|---:|---:|---:|---:|
| Actor start | $0.001 | $0.001 | $0.0008 | $0.00065 |
| 1,000 Telegram results | $3.00 | $2.50 | $2.25 | $2.00 |

For example, a Bronze run returning 100 matching messages costs $0.251: a $0.001 start plus 100 × $0.0025. A run that finds no matching posts is charged only the start event. Platform usage is included in these prices. You can set a maximum run charge in Apify to control spending.

AI enrichment is optional. When enabled, OpenAI usage is charged separately to your OpenAI account. Use `maxAiItems` and `aiBudgetUsd` to keep the attempted enrichment within a predictable bound. The Actor preserves deterministic raw matches if the AI budget is exhausted or an AI request fails.

### Coverage and responsible use

This Actor deliberately works without a Telegram account. That makes setup simple, but it also defines the coverage:

- It can discover Telegram posts exposed by public web search providers.
- It can inspect recent public preview pages for known public channels.
- It does **not** provide a complete index of Telegram.
- It does **not** access private channels, private groups, deleted posts, or content hidden behind membership or login.
- Public web indexes can be delayed, incomplete, region-dependent, or temporarily unavailable.
- Older messages may fall outside a channel's current public preview page.
- Views, forwards, reactions, edit timestamps, and media types are returned only when visible in the public source.

Provider gaps are not silently presented as complete results. Check the `OUTPUT` run summary, especially `coverage` and `incompleteProviders`, when completeness matters to your workflow.

You are responsible for using public Telegram data in accordance with applicable laws, platform terms, privacy requirements, and the rights of content authors. Avoid collecting or republishing personal data without a valid purpose.

### Troubleshooting

| Problem | What to check |
|---|---|
| No messages found | Try broader match mode, fewer required terms, no date/language filter, and one known public channel. |
| A channel returns no data | Confirm it is public and that `https://t.me/s/CHANNEL` opens without login. |
| Older posts are missing | Public preview pages expose a recent window; web search indexes are not complete archives. |
| `onlyNew` returns zero | The current message versions were already delivered by this `monitorId`; use a new ID only if you want a fresh checkpoint. |
| Some providers are incomplete | Inspect `incompleteProviders` in the `OUTPUT` run summary and retry later or enable Apify Proxy. |
| AI fields are empty | Confirm `aiMode: openai`, a valid secret API key, positive AI limits, and available OpenAI budget. |
| Too many irrelevant results | Use `exact` or `allWords`, add `includeTerms`/`excludeTerms`, restrict channels, or enable AI relevance. |

### FAQ

#### Can I search Telegram without an account?

Yes. This Actor uses public Telegram preview pages and public web search results, so it does not require a phone number, Telegram API ID, API hash, login code, or session string. The trade-off is partial public-source coverage rather than complete Telegram history.

#### Can it monitor a Telegram channel for new messages?

Yes, if the channel has a public preview page. Add it to `knownChannels`, set `onlyNew` to `true`, choose a stable `monitorId`, and schedule the run. The Actor stores its checkpoint between runs.

#### Can it search private Telegram groups or channels?

No. It does not join groups, authenticate a Telegram account, or access private content.

#### Is this a Telegram scraper or a Telegram API client?

It is a public-source Telegram scraper and monitoring Actor. It produces structured Telegram data through the Apify API, but it does not use an authenticated Telegram account or promise full MTProto/API coverage.

#### How are reposts and duplicate messages handled?

The Actor deduplicates the same message discovered more than once and can group exact or near-duplicate text into a shared `clusterId`. Cluster records retain counts and source relationships for narrative analysis.

#### Does AI change the original Telegram message?

No. AI enrichment adds separate relevance fields. The original `text`, channel, timestamp, and source URL remain unchanged, and evidence must be copied from the source message.

#### What export formats are available?

Apify datasets can be downloaded as JSON, JSONL, CSV, Excel, XML, or RSS. You can also read results using the Apify API and client libraries.

### Support

If a run behaves unexpectedly, share the public run URL or run ID, the non-secret input, and the `OUTPUT` run summary. Never include your OpenAI or Apify API token in a support request.

# Actor input Schema

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

Keywords and matching rules. Provide at least one query, an intent, or a known channel.

## `intent` (type: `string`):

Natural-language description of the signal you want. It is also used for AI relevance when AI mode is enabled.

## `knownChannels` (type: `array`):

Public channel usernames or t.me links. When provided, results are limited to these channels unless global web search is explicitly enabled below.

## `searchGlobalWeb` (type: `boolean`):

When channels are provided above, also run global public web discovery. Leave disabled to return results only from the specified channels. Global search runs automatically when no channels are provided.

## `includeChannels` (type: `array`):

Optional allowlist of public channel usernames or t.me links.

## `excludeChannels` (type: `array`):

Public channel usernames or t.me links to ignore.

## `fromDate` (type: `string`):

Only return messages published on or after this UTC date.

## `toDate` (type: `string`):

Only return messages published on or before this UTC date.

## `languages` (type: `array`):

Optional ISO 639-1 language codes such as en, es, or ru.

## `minViews` (type: `integer`):

Skip messages with a known view count below this value. Messages without a view count remain eligible.

## `minReactions` (type: `integer`):

Skip messages with a known reaction count below this value. Messages without reaction data remain eligible.

## `maxResultsPerQuery` (type: `integer`):

Maximum deterministic matches retained for each original query.

## `onlyNew` (type: `boolean`):

Skip messages delivered by previous runs with the same monitor ID.

## `monitorId` (type: `string`):

Stable identifier used for persistent checkpoints. Required when only-new mode is enabled.

## `webSearchProvider` (type: `string`):

Auto tries bounded public search providers in order and reports partial failures transparently.

## `expandQueriesWithAi` (type: `boolean`):

Generate a small bounded set of intent-preserving retrieval variants. Requires OpenAI mode and an API key.

## `aiMode` (type: `string`):

Off preserves raw deterministic results. OpenAI adds relevance evidence within the configured item and dollar budgets.

## `openaiApiKey` (type: `string`):

Optional encrypted API key used only when OpenAI enrichment is enabled. The OPENAI\_API\_KEY environment variable is also supported.

## `openaiModel` (type: `string`):

Model used for structured relevance and optional expansion.

## `relevanceThreshold` (type: `integer`):

Minimum AI relevance score retained in relevant-only alert mode.

## `clusterResults` (type: `boolean`):

Group exact and near-duplicate messages while preserving every source link.

## `generateDigest` (type: `boolean`):

Emit a compact run digest based on the resulting clusters.

## `maxAiItems` (type: `integer`):

Hard cap on messages sent for AI classification.

## `aiBudgetUsd` (type: `number`):

Conservative run budget. Enrichment stops before this estimate is exceeded and raw results are preserved.

## `alertMode` (type: `string`):

Return all deterministic matches or only AI-relevant matches when AI is enabled.

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

Optional proxy for public web and Telegram preview requests.

## Actor input object example

```json
{
  "queries": [
    {
      "text": "artificial intelligence",
      "mode": "allWords",
      "excludeTerms": []
    }
  ],
  "knownChannels": [],
  "searchGlobalWeb": false,
  "includeChannels": [],
  "excludeChannels": [],
  "languages": [],
  "maxResultsPerQuery": 100,
  "onlyNew": false,
  "webSearchProvider": "auto",
  "expandQueriesWithAi": false,
  "aiMode": "off",
  "openaiModel": "gpt-4.1-mini",
  "relevanceThreshold": 70,
  "clusterResults": true,
  "generateDigest": false,
  "maxAiItems": 200,
  "aiBudgetUsd": 1,
  "alertMode": "relevantOnly",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

No description

## `runSummary` (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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("i-scraper/telegram-keyword-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 = {}

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

```

## MCP server setup

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