# X (Twitter) Replies Scraper — Thread Context (`arjun_code/x-twitter-replies-scraper`) Actor

Export visible replies from public X (Twitter) posts by URL or ID. Get clean comment text, nested thread context, engagement, media, quoted posts, and detailed author profiles with automatic pagination—no X cookies, API key, or proxy setup.

- **URL**: https://apify.com/arjun\_code/x-twitter-replies-scraper.md
- **Developed by:** [Arjun AI](https://apify.com/arjun_code) (community)
- **Categories:** Social media, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.20 / 1,000 reply 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/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

**X (Twitter) Replies Scraper** exports visible comments and nested replies from public X posts. Paste one or more post URLs or numeric IDs to get clean reply text, parent-thread context, engagement metrics, media, quoted-post data, and detailed public author profiles.

The Actor follows X's recent reply pages automatically. Users do not need to supply an X login, cookies, API key, or proxy settings—add the posts and click **Start**.

### What can this X replies scraper do?

- Scrape replies from multiple public X or Twitter post URLs in one run.
- Follow reply pages automatically, with no manual cursor or next-page token.
- Distinguish direct comments from nested replies in the same conversation.
- Resolve the parent post, replied-to username, and replied-to display name when X returns the required context.
- Provide clean display text while preserving the full native reply text.
- Export engagement, media, quoted posts, and detailed public author profiles.
- Store each completed page immediately and keep those results if a later page fails.
- Export the Dataset as JSON, JSONL, CSV, Excel, XML, or RSS, or retrieve it through the Apify API.

#### Why use this Actor?

| Capability | How this Actor handles it |
| --- | --- |
| Setup | No user-supplied X account, cookies, API key, or proxy configuration |
| Pagination | Automatically follows the available reply pages for every source post |
| Thread context | Parent post ID, replied-to user ID, username, display name, and direct/nested classification |
| Analysis-ready text | Clean `reply_display_text` plus the complete native `reply_text` |
| Reliability | Automatic retries, duplicate removal, and retention of results already collected |
| Output design | Readable Overview and Detailed views, normalized flat fields, and optional raw X objects |
| Coverage claim | Reports the visible replies X returns instead of promising inaccessible or deleted comments |

This combination is useful when a flat list of comment text is not enough and the relationship between replies matters.

### How to scrape X replies and comments

1. Open the Actor's **Input** tab.
2. Paste one or more X post URLs or numeric post IDs into **X post IDs or URLs**.
3. Set **Maximum replies per post**. Keep the default `100`, choose another limit, or enter `0` to continue through the available recent replies.
4. Leave raw objects disabled unless your workflow needs X's internal response fields.
5. Click **Start**, then open the Dataset to preview or export the results.

#### Input fields

| Field | Description | Default |
| --- | --- | --- |
| `tweets` | Up to 50 unique numeric post IDs or full `x.com` / `twitter.com` status URLs. Duplicate IDs are requested once, and invalid values do not stop other valid posts. | Required |
| `maxRepliesPerTweet` | Maximum unique visible replies per source post. Use `0` to continue until X provides no more new visible replies. | `100` |
| `includeRawUser` | Adds the native reply-author object as `raw_user` from the existing X response. | `false` |
| `includeRawReply` | Adds the native Tweet object as `raw_reply` from the existing X response. | `false` |

Example input:

```json
{
  "tweets": [
    "https://x.com/naval/status/2100128104283091247",
    "2097815633828172097"
  ],
  "maxRepliesPerTweet": 100,
  "includeRawUser": false,
  "includeRawReply": false
}
```

Posts are processed sequentially. A run accepts up to 50 unique valid source posts; split larger batches across multiple runs. More posts and larger reply limits increase runtime and the number of billable results.

#### When should raw X objects be enabled?

Both raw options reuse data already present in the same TweetDetail response and do not create another X request. `raw_user` contains the reply author's native user object. `raw_reply` contains the native Tweet object and normally embeds author data again, so enabling both creates duplication and can make exports several times larger.

Keep both options disabled for normal exports. Enable them for debugging or when a native field that has not been normalized is required. Authentication cookies, tokens, passwords, and proxy details are never included.

### What X reply data can you extract?

#### Reply and conversation fields

- Reply post ID, URL, full text, clean display text, timestamp, language, and posting client.
- Conversation ID, parent post ID, replied-to user ID, username, and display name.
- `is_direct_reply`, which identifies replies to the requested source post versus nested replies returned in the same conversation.
- Reply, repost, like, quote, bookmark, and view counts when X returns them.
- Hashtags, mentions, expanded URLs, sensitivity status, images, and video variant metadata.

#### Quoted-post context

- Quoted post ID, URL, text, timestamp, and language.
- Quoted author ID, username, and display name.

#### Reply-author profile

- User ID, username, display name, bio, location, account creation time, profile URL, avatar, and banner.
- Follower, following, post, media, and like counts.
- Verification, professional categories, affiliation, labels, pinned posts, website, and public profile flags.

### Output example

Each successful Dataset row represents one visible reply. The example below is shortened; the Dataset schema contains the complete normalized record.

```json
{
  "status": "success",
  "source_tweet_id": "2097815633828172097",
  "source_tweet_url": "https://x.com/i/web/status/2097815633828172097",
  "reply_tweet_id": "2097842509372092418",
  "reply_tweet_url": "https://x.com/JordanSchachtel/status/2097842509372092418",
  "reply_text": "@FoxNews He spent six weeks at Anthropic, guys",
  "reply_display_text": "He spent six weeks at Anthropic, guys",
  "reply_created_at": "Thu Sep 10 00:20:04 +0000 2026",
  "reply_language": "en",
  "conversation_id": "2097815633828172097",
  "reply_to_tweet_id": "2097815633828172097",
  "reply_to_username": "FoxNews",
  "reply_to_name": "Fox News",
  "is_direct_reply": true,
  "reply_reply_count": 3,
  "reply_retweet_count": 3,
  "reply_like_count": 121,
  "reply_view_count": 3503,
  "reply_media": [],
  "reply_is_quote": false,
  "author_id": "535643852",
  "author_username": "JordanSchachtel",
  "author_name": "Jordan Schachtel",
  "author_followers_count": 302813,
  "author_blue_verified": true,
  "author_profile_url": "https://x.com/JordanSchachtel"
}
```

The **Overview** view emphasizes clean text, time, engagement, quote context, author identity, audience size, and clickable links. The **Detailed** view adds every normalized field. Optional native objects remain available in the complete Dataset record.

The `reply_*_count` fields describe engagement on the reply, not the source post. `reply_display_text` applies X's native display range so leading reply mentions do not obscure the comment, while `reply_text` preserves the complete text returned by X. `reply_source_url` comes from X's native `source` field; it is not constructed by the Actor.

### How much does it cost to scrape X replies?

This Actor uses pay-per-event pricing. One successfully stored reply produces one `reply-result` event.

| Apify plan | Price per successful reply | Example: 1,000 replies |
| --- | ---: | ---: |
| Free | $0.00035 | $0.35 |
| Bronze | $0.00030 | $0.30 |
| Silver | $0.00025 | $0.25 |
| Gold, Platinum, and Diamond | $0.00020 | $0.20 |

An `apify-actor-start` event costs $0.00005 per run. On the Free tier, 100 successful replies cost approximately **$0.03505**, and 1,000 cost approximately **$0.35005**, including one start event. Platform usage is included in the configured event prices.

Diagnostic rows with `invalid_input`, `not_found`, `no_results`, `partial`, `request_failed`, or `charge_limit_reached` do not create a `reply-result` charge. Use `maxRepliesPerTweet` and Apify's **Maximum cost per run** setting to control spending. The Actor page's **Pricing** tab is authoritative if prices change.

### Pagination, retries, and result limits

Reply pages are followed automatically. If a temporary request problem occurs, the Actor retries the same page up to five times and changes the request route when needed, so a retry does not intentionally skip part of the conversation.

Completed pages are stored immediately, and duplicate reply IDs are removed separately for each source post. Pagination stops when X provides no next page, repeats the same page, reaches the requested result or charge limit, or produces three consecutive pages without a new unique reply. The final log reports how many pages were requested and why collection stopped.

X may occasionally include unrelated posts in a conversation response. The Actor checks that every stored reply belongs to the requested conversation and has a parent post.

#### Why can the result count be lower than the number shown on X?

X decides which replies are exposed through its recent conversation timeline. Deleted, protected, withheld, spam-filtered, restricted, or otherwise unavailable replies may not be returned. X can also display counts that include content unavailable to the active session.

For that reason, the Actor returns **all unique visible replies provided by the paginated X response**, not a guaranteed copy of every reply represented by X's displayed counter. Nested replies are included when X returns them in the same conversation timeline.

#### Diagnostic statuses

| Status | Meaning | Reply-result charge |
| --- | --- | --- |
| `invalid_input` | The submitted value is not a numeric post ID or supported X / Twitter status URL; other valid inputs continue normally. | No |
| `not_found` | The source post was deleted, unavailable, or does not exist. | No |
| `no_results` | The source post exists, but X returned no visible replies. | No |
| `partial` | Earlier pages were stored before a later page failed. | No charge for the diagnostic row; stored replies remain billable |
| `request_failed` | The first page failed before a reply was stored. | No |
| `charge_limit_reached` | The run stopped at the configured maximum cost. | No |

### X replies scraper API and integrations

Use the Apify API to start a run from Python, JavaScript, a backend service, or any HTTP client:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/arjun_code~x-twitter-replies-scraper/runs?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "tweets": ["https://x.com/naval/status/2100128104283091247"],
    "maxRepliesPerTweet": 100
  }'
```

Runs can be automated with Apify schedules and webhooks. Results can be sent to Google Sheets, Make, Zapier, cloud storage, databases, or another system through the Dataset API and Apify integrations.

### Frequently asked questions

#### Do I need an X account, cookies, or an API key?

No. Users provide only public post URLs or IDs. Proxy routing and request credentials are handled inside the Actor.

#### Can it scrape replies from several X posts in one run?

Yes. Add multiple URLs or IDs to `tweets`. Every source post has its own pagination state, reply-ID deduplication set, and result limit.

#### Does it collect direct comments and replies to other comments?

Yes, when X returns them in the same conversation timeline. Use `is_direct_reply`, `reply_to_tweet_id`, `reply_to_username`, and `reply_to_name` to reconstruct the visible relationship.

#### Can I scrape every reply to a post?

Set `maxRepliesPerTweet` to `0` to continue through the available recent replies. However, no scraper can return replies that X does not expose. See the result-limit explanation above.

#### Can I export X comments to CSV or Excel?

Yes. Open the run's Dataset and choose JSON, JSONL, CSV, Excel, XML, or RSS. You can also retrieve records through the Dataset API.

#### Is scraping X replies legal?

This Actor processes publicly exposed post and profile data. Whether a particular use is lawful depends on the data, jurisdiction, and purpose. Do not collect or use personal data unlawfully, and follow X, Apify, and applicable privacy requirements.

### Related X (Twitter) Actors

| Actor | Best for |
| --- | --- |
| [X (Twitter) Media Downloader](https://apify.com/arjun_code/x-twitter-media-downloader) | Post details plus downloadable images, videos, GIFs, and X Articles |
| [X (Twitter) Retweeters Scraper](https://apify.com/arjun_code/x-twitter-retweeters-scraper) | Users who reposted or quoted a post, with quote-post context |
| [X (Twitter) Followers & Followings Scraper](https://apify.com/arjun_code/x-twitter-followers-followings-scraper) | Complete visible follower or following lists with profile data |
| [X (Twitter) People Search Scraper](https://apify.com/arjun_code/x-twitter-people-search-scraper) | Public X profiles matching keywords or search queries |

### Privacy and support

Internal cookies, proxy details, and authentication data are never written to the result Dataset. This independent Actor is not affiliated with, endorsed by, or sponsored by X Corp.

If a run fails or X changes its response format, open the Actor's **Issues** tab and include the Apify run ID, input, and expected behavior. Never include passwords, cookies, tokens, or other secrets.

# Actor input Schema

## `tweets` (type: `array`):

Enter up to 50 X posts, one per line. Each value may be a numeric post ID or a full x.com/twitter.com status URL. Duplicate post IDs are requested only once, invalid values are reported separately, and valid posts continue processing sequentially.

## `maxRepliesPerTweet` (type: `integer`):

Maximum number of unique visible replies returned for each source post. Enter 0 to continue until X provides no next page, repeats the same page, or returns three consecutive pages without a new unique reply.

## `includeRawUser` (type: `boolean`):

Adds the native reply-author object as raw\_user from the same X response. It makes records larger but does not send another request. Leave disabled for clean exports.

## `includeRawReply` (type: `boolean`):

Adds the native Tweet object as raw\_reply from the same X response. It can duplicate author data and significantly increase record size. Leave disabled unless you need X's internal fields.

## Actor input object example

```json
{
  "tweets": [
    "2097815633828172097"
  ],
  "maxRepliesPerTweet": 100,
  "includeRawUser": false,
  "includeRawReply": false
}
```

# Actor output Schema

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

Visible replies returned by X for the requested source posts.

# 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 = {
    "tweets": [
        "2097815633828172097"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("arjun_code/x-twitter-replies-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 = { "tweets": ["2097815633828172097"] }

# Run the Actor and wait for it to finish
run = client.actor("arjun_code/x-twitter-replies-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 '{
  "tweets": [
    "2097815633828172097"
  ]
}' |
apify call arjun_code/x-twitter-replies-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,arjun_code/x-twitter-replies-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/11p6xUOhbXDe28Crn/builds/SLbXDviYlyvUWGiLs/openapi.json
