# X Keyword Search with Mention & Reply Operators (`vexaloom-labs/x-keyword-search-with-mention-and-reply-operators`) Actor

Search X (Twitter) by keyword with filters for date, language, engagement, media, verification, mentioned handle, author, reply target, and conversation thread, plus Top/Latest sort.

- **URL**: https://apify.com/vexaloom-labs/x-keyword-search-with-mention-and-reply-operators.md
- **Developed by:** [vexaloom-labs](https://apify.com/vexaloom-labs) (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 $0.49 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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

## Twitter Keywords Scraper Pro

Collect public X (Twitter) posts without logging in, without cookies and without an API key.
Search by keyword, walk an author's recent timeline, fetch exact post URLs, or open a
conversation thread — then export clean rows with the author, engagement counts, media,
quoted post and reply context already filled in.

> **Coverage note:** X puts its own full search behind a login. This actor uses the public
> Bing News x.com index plus public post pages, so it returns a real subset of public X
> posts, not X's complete search index. That hard limit is explained below.

### What you get

Every dataset row is one post (`type: "post"`) with:

- **Post**: `id`, `url`, `text`, `createdAt`, `language`, `conversationId`
- **Engagement**: `likeCount`, `replyCount`, `retweetCount`, `quoteCount`, `bookmarkCount`,
  `viewCount`, `engagementRate`
- **Flags**: `isReply`, `isRetweet`, `isQuote`, `isNoteTweet`, `possiblySensitive`
- **Reply context**: `inReplyToTweetId`, `inReplyToUserId`, `inReplyToUsername`, `parentTweet`
- **Quote context**: `quotedTweetId`, nested `quotedTweet`
- **Entities**: `hashtags`, `mentions`, `urls`, `cashtags`
- **Media**: photo, video or GIF with `url`, `previewImageUrl`, `width`, `height`,
  `variants`, `durationSeconds`, `altText`
- **Author**: `id`, `username`, `name`, `bio`, `followers`, `following`, `location`,
  `website`, `profileImageUrl`, `bannerUrl`, `createdAt`, `postCount`, `mediaCount`,
  `verified`, `isBlueVerified`
- **Attribution**: `searchTerm` (keyword, handle, URL or conversation ID) and `collectedAt`

Empty values are omitted at every depth. Missing counters are omitted, never invented as
zero. An empty run writes a `RUN_SUMMARY` to the key-value store and leaves the dataset
empty — there are no status or sentinel rows.

### Four modes

| Mode | Input | What it collects |
|---|---|---|
| `search` | `keywords` | Public posts found for each keyword through the Bing News x.com index, optionally supplemented by X guest search when you supply a proxy. |
| `byAuthor` | `authorHandles` | The profile page's metadata and recent posts, plus the public syndication timeline (up to ~21 posts per author). |
| `byUrls` | `postUrls` | Exact posts from URLs or IDs, using the post page, syndication, FxTwitter and oEmbed fallbacks. |
| `conversation` | `conversationId` | The focal post plus the reply previews X renders publicly, with the focal post kept first. |

### Quick start

#### Keyword search

```json
{
  "mode": "search",
  "keywords": ["apify", "#AI", "OpenAI"],
  "maxItems": 50,
  "sort": "Latest",
  "language": "en"
}
```

#### Posts by author

```json
{
  "mode": "byAuthor",
  "authorHandles": ["@apify", "https://x.com/OpenAI"],
  "maxItems": 20
}
```

#### Specific post URLs

```json
{
  "mode": "byUrls",
  "postUrls": [
    "https://x.com/apify/status/2118015298603274372",
    "2117931222320259247"
  ]
}
```

#### Conversation thread

```json
{
  "mode": "conversation",
  "conversationId": "https://x.com/apify/status/2118015298603274372",
  "maxItems": 20
}
```

### Inputs

| Input | Type | Default | Notes |
|---|---|---|---|
| `mode` | select | `search` | `search`, `byAuthor`, `byUrls` or `conversation`. Required. |
| `keywords` | string list | – | Used by `search`. A single string is also accepted. |
| `authorHandles` | string list | – | Used by `byAuthor`. Accepts `@handle`, `handle` or a profile URL. |
| `postUrls` | string list | – | Used by `byUrls`. Accepts post URLs and bare IDs. |
| `conversationId` | text | – | Used by `conversation`. Accepts an ID or a post URL. |
| `maxItems` | integer 1–1000 | `20` | Per keyword/author in search and author modes; total cap in URL and conversation modes. |
| `sort` | select | `Top` | `Top` (engagement), `Latest` (newest), `Top + Latest` (top half by engagement, then the newest remaining posts). |
| `language` | select | `Any language` | Any language or an ISO-639-1 code. Applied after collection. |
| `dateFrom`, `dateTo` | date pickers | – | Inclusive UTC date bounds. |
| `excludeRetweets`, `excludeReplies` | boolean | `false` | Drop reposts or replies. |
| `onlyVerifiedUsers` | boolean | `false` | Keep verified or blue-check accounts. |
| `onlyImages`, `onlyVideos`, `onlyQuotes` | boolean | `false` | Keep photo posts, video/GIF posts, or quote posts. |
| `minimumLikes`, `minimumRetweets`, `minimumReplies` | integer | – | Drop rows below the threshold; rows whose count is unavailable are dropped and reported. |
| `mentioning`, `author`, `inReplyTo` | text | – | Client-side operator filters: mention handle, author handle, reply target handle. |
| `proxyConfiguration` | proxy | – | Optional. Nothing needs a proxy; when supplied it is also used for the best-effort guest search supplement. |

No cookie, token, API key or proxy field is required. Legacy saved inputs that use
`maxTweets`, `searchType`, `startDate`, `endDate` or `tweetLanguage` keep working: the actor
maps those keys in code even though they no longer appear in the form.

### How collection works

1. **Discovery (`search`)** — queries Bing News RSS for `site:x.com <keyword>` with plain
   variants (the keyword, quoted phrase, `x.com`, `twitter`, `news`, `today`, `2026`,
   `update`, `announcement`) and collects unique post IDs. A small job stops after one
   request; large jobs page through `first=13,26,39,52` with a roughly 460-ID ceiling.
2. **Hydration** — fetches each ID from the public syndication CDN in parallel. Deleted,
   protected and tombstoned posts are skipped and counted in the summary. Local probes
   hydrated 197 of 202 IDs (97.5%) and 193 of 199 (97.0%).
3. **Profile and post pages** — `byAuthor` reads the logged-out `x.com/<handle>` page (exact
   profile metadata and recent posts) and falls back to the syndication profile timeline.
   `byUrls` and `conversation` read the logged-out post page, which embeds the focal post,
   quoted post and visible reply previews.
4. **Fallback enrichment** — FxTwitter fills missing view/bookmark/retweet/quote counters
   and author profile fields. oEmbed is the last resort for a known post ID. A mirror
   outage never fails a run; missing fields stay omitted.
5. **Client-side filters** — X-style operators (`mentioning`, `author`, `inReplyTo`) and
   every date/language/engagement/media/verification/flag filter are applied locally after
   hydration. The index never receives opaque operator text.
6. **Deterministic output** — dedupe by post ID, sort, cap, recompute `engagementRate` and
   emit omit-empty rows.

### Coverage and honest limits

- **Full X search requires a login.** X's search page redirects logged-out visitors to a
  login wall, and the guest SearchTimeline endpoint answers only a minority of requests
  and virtually never from datacenter IPs. This actor therefore uses the public index as
  its primary discovery path. Building full search coverage would require a logged-in
  account pool or a paid provider, which this actor deliberately does not use.
- **The index is smaller than X search.** A keyword usually yields tens to a few hundred
  public posts, weighted toward newsworthy and recently linked posts. Broad one-word
  keywords can hit the roughly 460-candidate discovery ceiling; narrow keywords may yield only a
  handful.
- **`Top` is an engagement sort.** It orders by likes and reposts; it is not X's private
  ranking model. `Top + Latest` combines an engagement half with the newest remaining posts.
- **Conversation depth is a preview.** Logged-out X renders the focal post plus a few
  visible replies, so a thread returns those posts, not every reply.
- **Not covered:** geo/place filters, People/Lists tabs, follower/following lists,
  sentiment/AI scoring and full-text search beyond the index. These need endpoints that
  are not public without a login.

### FAQ

**Do I need cookies, a login or an API key?**
No. The actor is cookieless and keyless. A proxy is optional; the default run works without
one and never creates a paid proxy group on its own.

**Why do I get fewer posts than the X search box shows?**
X's full search is login-gated. The actor reads the public Bing News x.com index and public
post pages, which cover a real but smaller subset of public posts. That is the documented
hard limit, not a bug.

**How many posts can one keyword return?**
The discovery buffer is capped at roughly 460 unique IDs, but the practical yield is usually tens
to a few hundred per keyword, depending on how many public posts the index knows. `maxItems`
still caps what is emitted.

**How fresh are the results?**
Discovery favours recently indexed and newsworthy posts, and each post's exact timestamp
comes from X's public payload. Use `dateFrom`/`dateTo` to keep only the window you need.

**Does `Top` match X's Top tab?**
No. X does not expose its ranking model publicly, so `Top` sorts the collected posts by
likes and reposts. `Latest` sorts by the real post timestamp.

**Why did a run return nothing?**
The dataset stays empty and the key-value store `RUN_SUMMARY` says why: no indexed posts,
all candidates deleted/tombstoned, every post removed by filters, or invalid input. The
status message shows the same reason. There are no placeholder rows.

**Why are view or bookmark counts missing on some rows?**
Syndication does not expose every counter. The actor asks FxTwitter to fill the gaps, but
when the mirror also lacks a value the field is omitted rather than fabricated.

**Can I get replies and quotes?**
Yes. Reply IDs/handles and the parent post are emitted when X exposes them, and quoted posts
are nested under `quotedTweet` with `quotedTweetId`. `conversation` mode adds the visible
reply previews of a thread.

**Is the actor affiliated with X?**
No. It reads only public, logged-out pages and public mirrors. It does not bypass a login,
sell account access, or require your credentials.

### Output summary

The default dataset view is called **Posts**. For every run, the `RUN_SUMMARY` key in the
default key-value store records `status` (`complete`, `partial` or `empty`), mode, candidate
and hydrated counts, emitted rows, dropped-filter counts, index coverage and elapsed time.

# Actor input Schema

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

Search by keyword, collect an author's posts, fetch specific post URLs, or open a conversation thread.

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

Words, phrases or hashtags to search for. Each keyword is collected separately and every row shows the keyword that found it (searchTerm).

## `authorHandles` (type: `array`):

Used by the 'Posts by author' mode. Accepts @handle, handle, or https://x.com/handle profile URLs.

## `postUrls` (type: `array`):

Used by the 'Specific post URLs' mode. Accepts x.com or twitter.com post links and bare post IDs.

## `conversationId` (type: `string`):

Used by the 'Conversation thread' mode. Paste the root post ID or a post URL in that thread.

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

Stop after this many posts per keyword or author. The URL and conversation modes use it as a total cap.

## `sort` (type: `string`):

Latest is newest first. Top is ordered by likes and reposts. Top + Latest returns the top half by engagement, then the newest remaining posts.

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

Only keep posts in this language. The default searches every language.

## `dateFrom` (type: `string`):

Only keep posts published on or after this date (UTC).

## `dateTo` (type: `string`):

Only keep posts published on or before this date (UTC).

## `excludeRetweets` (type: `boolean`):

Drop reposts and keep original posts only.

## `excludeReplies` (type: `boolean`):

Drop replies and keep top-level posts only.

## `onlyVerifiedUsers` (type: `boolean`):

Keep posts from verified or blue-check accounts only.

## `onlyImages` (type: `boolean`):

Keep posts that contain at least one photo.

## `onlyVideos` (type: `boolean`):

Keep posts that contain at least one video or GIF.

## `onlyQuotes` (type: `boolean`):

Keep posts that quote another post.

## `minimumLikes` (type: `integer`):

Drop posts below this like count. Posts whose count is unavailable are dropped and reported in the run summary.

## `minimumRetweets` (type: `integer`):

Drop posts below this repost count. Counts are filled from the public fallback source when available.

## `minimumReplies` (type: `integer`):

Drop posts below this reply count. Posts with no available reply count are dropped and reported.

## `mentioning` (type: `string`):

Only keep posts that mention this handle (with or without @). Applied after collection.

## `author` (type: `string`):

Only keep posts written by this handle (with or without @).

## `inReplyTo` (type: `string`):

Only keep posts that are replies to this handle (with or without @).

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

Optional. No proxy is needed. If supplied, it is used for the best-effort guest search supplement as well as page requests.

## Actor input object example

```json
{
  "mode": "search",
  "keywords": [
    "web scraping",
    "#AI",
    "OpenAI"
  ],
  "authorHandles": [
    "@apify",
    "https://x.com/OpenAI"
  ],
  "postUrls": [
    "https://x.com/apify/status/2118015298603274372"
  ],
  "maxItems": 3,
  "sort": "Latest",
  "language": "Any language",
  "excludeRetweets": false,
  "excludeReplies": false,
  "onlyVerifiedUsers": false,
  "onlyImages": false,
  "onlyVideos": false,
  "onlyQuotes": false
}
```

# Actor output Schema

## `tweets` (type: `string`):

Dataset containing one row per collected X post, deduplicated by post ID.

# 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 = {
    "mode": "search",
    "keywords": [
        "apify"
    ],
    "maxItems": 3,
    "sort": "Latest",
    "language": "Any language",
    "excludeRetweets": false,
    "excludeReplies": false,
    "onlyVerifiedUsers": false,
    "onlyImages": false,
    "onlyVideos": false,
    "onlyQuotes": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("vexaloom-labs/x-keyword-search-with-mention-and-reply-operators").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 = {
    "mode": "search",
    "keywords": ["apify"],
    "maxItems": 3,
    "sort": "Latest",
    "language": "Any language",
    "excludeRetweets": False,
    "excludeReplies": False,
    "onlyVerifiedUsers": False,
    "onlyImages": False,
    "onlyVideos": False,
    "onlyQuotes": False,
}

# Run the Actor and wait for it to finish
run = client.actor("vexaloom-labs/x-keyword-search-with-mention-and-reply-operators").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 '{
  "mode": "search",
  "keywords": [
    "apify"
  ],
  "maxItems": 3,
  "sort": "Latest",
  "language": "Any language",
  "excludeRetweets": false,
  "excludeReplies": false,
  "onlyVerifiedUsers": false,
  "onlyImages": false,
  "onlyVideos": false,
  "onlyQuotes": false
}' |
apify call vexaloom-labs/x-keyword-search-with-mention-and-reply-operators --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,vexaloom-labs/x-keyword-search-with-mention-and-reply-operators"
        }
    }
}
```

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/xgRc7Nc7IkbNcF3bC/builds/I7cduHm9oKbw9FGRa/openapi.json
