# X (Twitter) Replies Scraper (`maximedupre/twitter-x-reply-scraper`) Actor

Collect public replies from X posts you provide by URL or ID. Choose direct replies or deeper surfaced conversation coverage, then get reply text, source links, author details, engagement, dates, language, and public media references when available.

- **URL**: https://apify.com/maximedupre/twitter-x-reply-scraper.md
- **Developed by:** [Maxime Dupré](https://apify.com/maximedupre) (community)
- **Categories:** Social media, Marketing, Developer tools
- **Stats:** 3 total users, 2 monthly users, 85.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.01 / 1,000 replies

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?

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

### 💬 Collect public X replies from known posts

Researchers, marketers, and developers can use this X (Twitter) reply scraper with public post URLs or IDs they already have. It saves structured reply rows with reply text, source links, conversation context, available author details, engagement counts, publish time, language, and public media references. This turns known public conversations into data you can review or use in another workflow. It does not find source posts by keyword, profile, or timeline.

Use it to:

- Collect public replies from a supplied post with **[Twitter Replies Scraper](https://apify.com/maximedupre/twitter-x-reply-scraper/examples/twitter-replies-scraper)**.
- Pull reply text into a dataset with **[Tweet Reply Scraper](https://apify.com/maximedupre/twitter-x-reply-scraper/examples/tweet-reply-scraper)**.
- Save replies from X post URLs or IDs with **[Scrape Twitter Replies](https://apify.com/maximedupre/twitter-x-reply-scraper/examples/scrape-twitter-replies)**.
- Review deeper conversation coverage with **[Scrape X Replies](https://apify.com/maximedupre/twitter-x-reply-scraper/examples/scrape-x-replies)**.
- Keep reply links and author details together with **[Twitter Reply Scraper](https://apify.com/maximedupre/twitter-x-reply-scraper/examples/twitter-reply-scraper)**.

#### 🧾 Reply rows with source context

Each saved row represents one public reply found for a supplied X post. The row keeps the reply ID, text, and link together with the source post. When X exposes them, it also includes parent reply and conversation details, public author fields, engagement counts, publish time, language, and media links with their types.

Only public data that X surfaces is available. The Actor does not promise every reply in a large conversation, and it does not download media files.

#### ▶️ Run a public X reply collection

1. Add one or more public X post URLs or post IDs.
2. Choose **Direct replies** or **Deeper conversation**.
3. Set **Maximum reply records**, or leave it empty to return all available replies until the source is exhausted.
4. Run the Actor and open the default dataset.

The selected conversation depth applies to every supplied post in the run. Use a direct post URL or ID when you already know the source. This Actor does not discover source posts from keywords, profiles, or timelines.

#### ⚙️ Input

**Input fields**

| Field | Type | What it does |
|---|---|---|
| `postUrlsOrIds` | string\[] | Lists one or more public X post URLs or post IDs. Each value identifies one source post. |
| `conversationDepth` | string | Chooses direct replies or deeper surfaced conversation coverage for each source post. |
| `maxItems` | integer (optional) | Stops after this many reply records. Leave it empty to return all available replies until the source is exhausted. |

**Example input**

This is the public input from a successful current-beta run:

```json
{
  "postUrlsOrIds": [
    "https://x.com/apify/status/2093346503326626183"
  ],
  "conversationDepth": "direct",
  "maxItems": 5
}
```

Use an empty **Maximum reply records** field when you want all available replies until the source is exhausted. The field is an optional work limit, not a fixed source maximum.

#### 🧾 Output

**Run output**

| Field | Type | What it does |
|---|---|---|
| `dataset` | string (URL) | Opens the collected reply rows in the default dataset. |

**Dataset row**

Every dataset row has the same shape. Optional values are omitted when X does not expose them.

| Field | Type | What it does |
|---|---|---|
| `id` | string (required) | The stable X post ID of the reply. |
| `text` | string (required) | The reply text exposed by X. |
| `url` | string (optional) | A public URL for opening the reply on X. |
| `sourcePost` | object (required) | The public source post whose replies were collected. |
| `sourcePost.id` | string (required) | The stable X post ID of the supplied source post. |
| `sourcePost.url` | string (optional) | A public URL for opening the supplied source post on X. |
| `parentReply` | object (optional) | The available reply that this reply directly follows. |
| `parentReply.id` | string (required in object) | The stable X post ID of the parent reply. |
| `parentReply.url` | string (optional) | A public URL for opening the parent reply on X. |
| `parentReply.text` | string (optional) | The parent reply text when X exposes it. |
| `conversationId` | string (optional) | The stable X conversation ID for the reply when X exposes it. |
| `author` | object (optional) | Available public profile details for the reply author. |
| `author.handle` | string (optional) | The author's X handle. |
| `author.name` | string (optional) | The author's displayed name. |
| `author.profileUrl` | string (optional) | A public URL for the author's X profile. |
| `author.avatarUrl` | string (optional) | A public URL for the author's profile image. |
| `author.bio` | string (optional) | The author's public profile bio. |
| `author.followersCount` | integer (optional) | The follower count shown on the author's public profile. |
| `author.followingCount` | integer (optional) | The number of accounts shown as followed by the author. |
| `author.verified` | boolean (optional) | Whether the author's public profile is marked as verified. |
| `engagement` | object (optional) | Engagement counts shown for the reply by X. |
| `engagement.likesCount` | integer (optional) | The number of likes shown for the reply. |
| `engagement.repliesCount` | integer (optional) | The number of replies shown for the reply. |
| `engagement.repostsCount` | integer (optional) | The number of reposts shown for the reply. |
| `engagement.quotesCount` | integer (optional) | The number of quote posts shown for the reply. |
| `engagement.bookmarksCount` | integer (optional) | The number of bookmarks shown for the reply. |
| `engagement.viewsCount` | integer (optional) | The number of views shown for the reply. |
| `publishedAt` | date-time string (optional) | The time when the reply was published on X. |
| `language` | string (optional) | The language reported for the reply by X. |
| `media` | object\[] (optional) | Public media references attached to the reply. |
| `media[].url` | string (required in item) | The public URL of the attached media. |
| `media[].type` | string (required in item) | The type reported for the attached media. |

**Example dataset row**

This complete row comes from the successful current-beta conversation run:

```json
{
  "id": "2093346571664433347",
  "text": "@maximehugodupre How he got started shipping on Apify ↓ https://t.co/TBRE7y2Aqs",
  "url": "https://x.com/apify/status/2093346571664433347",
  "sourcePost": {
    "id": "2093346503326626183",
    "url": "https://x.com/apify/status/2093346503326626183"
  },
  "parentReply": {
    "id": "2093346536486748433",
    "url": "https://x.com/apify/status/2093346536486748433",
    "text": "@maximehugodupre Maxime has been building since 2025 ↓ https://t.co/RhNuiMAGmk"
  },
  "conversationId": "2093346503326626183",
  "author": {
    "handle": "apify",
    "name": "Apify",
    "profileUrl": "https://x.com/apify",
    "avatarUrl": "https://pbs.twimg.com/profile_images/2036008913192316928/yuW3cobE_normal.png",
    "bio": "Thousands of Actors to automate your business, get real-time web data, and integrate your apps and agents.  ➡️  https://t.co/rySkh8qnak • https://t.co/PiUfLvrTQ2 • https://t.co/x4G1meKY5i",
    "followersCount": 16149,
    "followingCount": 300,
    "verified": false
  },
  "engagement": {
    "likesCount": 0,
    "repliesCount": 1,
    "repostsCount": 0,
    "quotesCount": 0,
    "bookmarksCount": 0,
    "viewsCount": 50
  },
  "publishedAt": "2026-08-28T14:34:49.000Z",
  "language": "en",
  "media": [
    {
      "url": "https://pbs.twimg.com/media/HQ0Pm0vXwAA_boL.png",
      "type": "photo"
    }
  ]
}
```

#### 💳 Pricing

This Actor uses pay-per-event pricing. The primary event is charged when one public reply is successfully collected and saved as a dataset row. The current price is shown in Apify's Pricing tab.

Use **Maximum reply records** to set an optional work limit. Leaving it empty returns all available replies until the source is exhausted.

#### 🔌 Integrations

https://www.youtube.com/watch?v=bNACk1\_S\_6w\&list=PLObrtcm1Kw6MUrlLNDbK9QRg8VDJg0gOW\&index=4

Open the default dataset in Apify or use the Apify API and dataset export tools to read the structured reply rows in another workflow.

#### ❓ FAQ

##### What if the source post is private, deleted, suspended, age-restricted, or login-only?

Only public replies that X surfaces can be returned. An unavailable source may produce no reply rows, and the Actor does not bypass access limits.

##### Does deeper conversation coverage return every reply?

No. It can include deeper replies that X publicly surfaces, but it does not guarantee every reply in a large conversation.

##### What is the difference between Direct replies and Deeper conversation?

Direct replies collect replies to the supplied post. Deeper conversation can also include surfaced replies from the conversation around that post.

##### What happens when Maximum reply records is empty?

The Actor continues until the source is exhausted and returns all available replies it can collect. The source, not a fixed number in the schema, controls the available total.

##### Can I submit more than one source post?

Yes. Add one or more public X post URLs or IDs. The selected conversation depth applies to every source post in that run.

##### Does this Actor find posts by keyword or profile?

No. Submit the public post URLs or IDs you want to read. The Actor does not discover source posts by keyword, profile, or timeline.

##### Which author and engagement fields are included?

Each row can include the public author details and engagement counts that X exposes, along with publish time and language. Missing optional values are left out.

##### Does the Actor download reply media?

No. It returns public media URLs and media types when X exposes them. It does not download or store the media bytes.

##### Can I use it for change tracking across runs?

No. The Actor collects the public replies available for the supplied posts in that run. It does not provide historical monitoring, change tracking, or cross-run alerts.

### 📝 Changelog

**v0.0** (21-09-2026)

- Initial release.

### 🆘 Support

For issues, questions, or feature requests, [file a ticket](https://console.apify.com/actors/maximedupre~twitter-x-reply-scraper/issues) and I'll fix or implement it in less than 24h 🫡

### 🔗 Related Actors

- [Twitter Scraper](https://apify.com/maximedupre/twitter-scraper) finds public X posts and profiles when you need to discover source posts before collecting replies.
- [Twitter Media Scraper](https://apify.com/maximedupre/twitter-media-scraper) collects direct links for public images, videos, and GIFs attached to X posts.
- [Twitter Retweet Checker](https://apify.com/maximedupre/twitter-retweet-checker) checks whether submitted usernames retweeted submitted public posts.
- [Twitter Article Scraper](https://apify.com/maximedupre/twitter-article-scraper) extracts public long-form X Articles from known post URLs or IDs.
- [Twitter Screenshot Generator](https://apify.com/maximedupre/twitter-screenshot-generator) saves screenshots of known public X posts for reports or archives.

**Made with ❤️ by Maxime Dupré**

# Actor input Schema

## `postUrlsOrIds` (type: `array`):

Enter one or more public X post URLs or post IDs. Each item identifies one source post whose replies will be collected.

## `conversationDepth` (type: `string`):

Choose which replies to collect for each source post. Direct replies collect replies to the supplied post. Deeper conversation coverage also includes surfaced replies from the conversation.

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

Optionally stop after this many reply records. Leave this field empty to return all available replies until the source is exhausted.

## Actor input object example

```json
{
  "postUrlsOrIds": [
    "https://x.com/apify/status/2093346503326626183"
  ],
  "conversationDepth": "direct",
  "maxItems": 5
}
```

# Actor output Schema

## `dataset` (type: `string`):

Open the collected reply records in the default dataset.

# 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 = {
    "postUrlsOrIds": [
        "https://x.com/apify/status/2093346503326626183"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("maximedupre/twitter-x-reply-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 = { "postUrlsOrIds": ["https://x.com/apify/status/2093346503326626183"] }

# Run the Actor and wait for it to finish
run = client.actor("maximedupre/twitter-x-reply-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 '{
  "postUrlsOrIds": [
    "https://x.com/apify/status/2093346503326626183"
  ]
}' |
apify call maximedupre/twitter-x-reply-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,maximedupre/twitter-x-reply-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/szOBU5b3LyiSOT4Mi/builds/1qqexMRvouXfl6dam/openapi.json
