# Twitter (X) Search Scraper API (`tweetapi/twitter-x-search-scraper`) Actor

Search public X/Twitter posts by keyword and export up to 500 results per run. Choose Latest, Top, Photos, or Videos. Results include post text, author details, engagement metrics, media, and URLs. No X login or API key required. Pay $0.25 per 1,000 results plus $0.001 per run.

- **URL**: https://apify.com/tweetapi/twitter-x-search-scraper.md
- **Developed by:** [TweetAPI](https://apify.com/tweetapi) (community)
- **Categories:** Social media, Lead generation, Automation
- **Stats:** 4 total users, 3 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.25 / 1,000 tweet results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

Search public X/Twitter posts with one query per run. Choose `Latest`, `Top`, `Photos`, or
`Videos`, then export the results in JSON, CSV, Excel, or another format supported by Apify.

Each result can include the post text, author details, engagement metrics, media, URLs, and
relationship IDs. You do not need an X login, cookies, or your own TweetAPI key.

### What you get

- Save up to 500 unique posts as stable `tweet-result-v1` Dataset records.
- Export the Dataset or send it to another Apify integration.
- Keep results already written if a later page fails.
- Check counts, limits, and the stop reason in `RUN_REPORT`.

Common uses include brand monitoring, media research, account or language searches, and collecting
photo or video posts for further analysis.

### Quick start

Enter one query, choose a mode, and set the maximum number of posts. For example:

```json
{
  "query": "from:OpenAI lang:en",
  "mode": "Latest",
  "maxItems": 100
}
```

`query` is required. `mode` defaults to `Latest`, and `maxItems` defaults to 100.

#### Query examples

| Goal                       | Query                        | Suggested mode    |
| -------------------------- | ---------------------------- | ----------------- |
| Posts from an account      | `from:OpenAI`                | `Latest`          |
| An exact phrase in English | `"machine learning" lang:en` | `Latest` or `Top` |
| A hashtag                  | `#Bangkok`                   | `Latest`          |
| Photos from an account     | `from:NASA`                  | `Photos`          |
| Videos about a topic       | `space exploration`          | `Videos`          |

You can use X Search operators to narrow the query. The Actor sends the query as written. It rejects
`filter:news` before making a TweetAPI request because that operator is unreliable in this workflow.

### Use it through the Apify API

Open the **API** menu on the Actor page to copy a request for cURL, JavaScript, Python, or another
supported client. Send the same `query`, `mode`, and `maxItems` fields that you use in Apify Console.
Each call starts one asynchronous Actor run. Read the records from the default Dataset or use the
`results` URL in the run output. You can also schedule runs or connect them to webhooks and
integrations. The Actor does not run as an always-on HTTP service.

### Search modes

| Mode     | What it returns                                                              |
| -------- | ---------------------------------------------------------------------------- |
| `Latest` | Recent posts from the Latest Search view.                                    |
| `Top`    | Posts from the relevance-ranked Top Search view. Non-post cards are skipped. |
| `Photos` | Posts from the photo-focused Search view, with supported media in `media`.   |
| `Videos` | Posts from the video-focused Search view, with supported media in `media`.   |

X Search controls the order and availability of results. Narrow queries and media modes can return
fewer posts than requested.

### Output

The Actor writes each post to the default Dataset as a `tweet-result-v1` record. Open **Output** or
**Storage** to view the results as a table. Apify can export the Dataset as JSON, JSONL, CSV, Excel,
XML, RSS, or HTML.

#### Dataset fields

| Field                                                 | What it contains                                                            |
| ----------------------------------------------------- | --------------------------------------------------------------------------- |
| `schemaVersion`, `recordType`, `recordId`, `workflow` | Record and workflow identifiers.                                            |
| `source`                                              | Search mode and one-based source page number.                               |
| `id`, `url`, `conversationId`                         | Post ID, public X URL, and conversation ID when available.                  |
| `text`, `lang`, `createdAt`, `type`                   | Post content and metadata.                                                  |
| `author`                                              | Author ID, username, name, profile URL, avatar URL, and verification flags. |
| `metrics`                                             | Reply, repost, quote, like, bookmark, and view counts when available.       |
| `replyTo`, `quotedTweetId`, `retweetedTweetId`        | Reply, quote, and repost relationships when available.                      |
| `media`                                               | Photo, video, or animated GIF URLs and available metadata.                  |
| `entities`                                            | Hashtags, mentions, expanded URLs, and symbols.                             |
| `possiblySensitive`                                   | The sensitive-content flag when available.                                  |

Missing fields remain `null` or an empty array. A missing metric is `null`, not zero.

#### Run report

The default key-value store contains `RUN_REPORT`. It records the status, stop reason, limits, counts,
Dataset ID, event name, and a safe warning or error category. It does not contain the query, post
text, cursors, credentials, headers, or raw responses.

### Pricing

The Actor currently charges:

- $0.001 when a run starts.
- $0.00025 for each `tweet-result-v1` record written to the default Dataset.

Platform usage is included. The **Pricing** tab is the source of truth for the current prices.

| Written results | Approximate total price |
| --------------- | ----------------------- |
| 20              | $0.006                  |
| 100             | $0.026                  |
| 500             | $0.126                  |

These examples assume that the run writes every requested result. Set Apify's maximum total charge
to limit spending. `maxItems` limits result events but does not replace the charge limit. A run that
reaches the charge limit stops with `charge_limit` and keeps the records already written.

### Run limits

Every run uses one query, one mode, and one request at a time. The Actor also applies these limits:

- 100 unique posts by default and no more than 500.
- No more than 30 TweetAPI requests.
- No more than 300 seconds for the search workflow.
- No automatic retries.

`maxItems` is a limit, not a promise. A run can return fewer posts because the query has fewer
matches, results contain duplicate Tweet IDs, pages contain no usable posts, or another limit is
reached. The Actor removes duplicate Tweet IDs within the run.

### Empty, partial, and failed runs

An empty search is successful and writes zero items. If TweetAPI returns cursors with empty pages,
the Actor checks at most two consecutive pages before completing the run.

A run is partial if it stops at the request, time, or charge limit, a repeated cursor, or two pages
that make no progress after results have appeared. Authentication, rate-limit, TweetAPI,
invalid-response, Dataset, and checkpoint errors fail the run. The Actor does not retry failed
TweetAPI requests automatically. In both cases, results already written stay in the Dataset.

### Recovery and deduplication

The Actor saves a checkpoint after each completed page. After an Apify migration, it can continue
from the latest checkpoint. Recovery is at least once, not exactly once. A page can be written again
if the process stops between the Dataset write and the checkpoint. Remove downstream duplicates with
`id` or `recordId`, and keep automatic restart on error disabled.

### Privacy and responsible use

Apify stores the query as run input according to your account's access and retention settings. The
Actor does not copy it into logs, Dataset records, or `RUN_REPORT`. It also keeps credentials,
headers, cursors, raw responses, and TweetAPI error bodies out of logs and `RUN_REPORT`.

Post text and public metadata go to the run's Dataset. The Actor manages its TweetAPI key and does
not accept one in the run input.

Use this Actor only for lawful purposes. Follow applicable laws, X's terms, Apify's terms, and the
privacy and data-retention rules that apply to your use case. Do not use the data for harassment,
unlawful surveillance, or prohibited sensitive profiling.

### Troubleshooting

- **Fewer posts than `maxItems`:** Check `RUN_REPORT.stopReason`. The query may have fewer matches, or
  the run may have skipped duplicates or reached another limit.
- **`filter:news` is rejected:** The operator is unreliable in this workflow, so the Actor stops
  before making a TweetAPI request.
- **Some fields are `null`:** TweetAPI does not return every field for every post. A missing metric is
  different from zero.

After a rate-limit or TweetAPI failure, keep any results already written and retry later if
appropriate. The Actor does not retry automatically.

### Support

Use the support channel on this Actor's Store page. Include the Apify run ID, run time, Search mode,
`RUN_REPORT.stopReason`, and the item and request counts. Do not send credentials, headers, raw
responses, or other secrets. You can omit a sensitive query from the initial report.

### Disclosure

TweetAPI is independent. Not affiliated with X Corp.

# Actor input Schema

## `query` (type: `string`):

Enter the X/Twitter search query. Apify stores it as run input. The Actor does not copy it to logs, Dataset records, or RUN\_REPORT. The Actor rejects filter:news because that operator is unreliable.

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

Choose the X Search view to use: Latest, Top, Photos, or Videos.

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

Set the maximum number of unique posts to save. The default is 100 and the maximum is 500. The final count can be lower if the query has fewer matches or the run reaches another limit.

## Actor input object example

```json
{
  "query": "from:OpenAI lang:en",
  "mode": "Latest",
  "maxItems": 100
}
```

# Actor output Schema

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

Open the default Dataset to view tweet-result-v1 records as a table or export them in a format supported by Apify.

## `runReport` (type: `string`):

Open the search-run-report-v1 record to check the outcome, stop reason, limits, and counts. It does not contain the query, post text, cursors, credentials, headers, or raw responses.

# 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 = {
    "query": "from:OpenAI lang:en"
};

// Run the Actor and wait for it to finish
const run = await client.actor("tweetapi/twitter-x-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 = { "query": "from:OpenAI lang:en" }

# Run the Actor and wait for it to finish
run = client.actor("tweetapi/twitter-x-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 '{
  "query": "from:OpenAI lang:en"
}' |
apify call tweetapi/twitter-x-search-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tweetapi/twitter-x-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/9057jzXTntFQ1bUA6/builds/WltDIMvtbBV0cLGLv/openapi.json
