# Twitter Comments Scraper - Replies and Quotes (`toolzerhub/twitter-comments-scraper`) Actor

Export the comments under any tweet: every reply, ordered by relevance, newest or most liked, plus the tweets that quote it if you want them. Paste tweet links or IDs. Each row has the text, author, time and counts.

- **URL**: https://apify.com/toolzerhub/twitter-comments-scraper.md
- **Developed by:** [ToolzerHub](https://apify.com/toolzerhub) (community)
- **Categories:** Social media, Automation, Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

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

## Twitter Comments Scraper — Replies and Quotes

Export the comments under any tweet — every reply X lists, ordered by relevance, newest or most liked — and, if you want them, the tweets that quote it. Paste tweet links or IDs. Each row is one reply or quote with its text, author, time and counters.

### Input

| Field | Type | Default | What it does |
|---|---|---|---|
| **`postUrls`** | list of text | — | **Required.** Tweet links (`https://x.com/elonmusk/status/2110947164512038931`) or bare IDs. One list can mix both. |
| **`replySort`** | `relevance` / `latest` / `likes` | `relevance` | `relevance` is X's default order. `latest` is newest first. `likes` puts the most liked first. |
| **`includeQuotes`** | boolean | `false` | After a tweet's replies, also save the tweets that quote it. |
| **`maxItems`** | integer | `100` | Caps the whole run, across every tweet. `0` means no limit. |

```json
{
  "postUrls": ["https://x.com/elonmusk/status/2110947164512038931"],
  "replySort": "likes",
  "includeQuotes": true,
  "maxItems": 200
}
```

### Output

One row per reply or quote.

| Field | What it holds |
|---|---|
| **`id`**, **`url`** | The reply's ID and link |
| **`text`**, **`lang`**, **`created_at`** | What it says, its language, when it was posted |
| **`like_count`**, **`reply_count`**, **`repost_count`**, **`quote_count`**, **`bookmark_count`**, **`view_count`** | The six counters |
| **`author_handle`**, **`author_name`**, **`author_id`**, **`author_followers_count`**, **`author_is_blue_verified`**, **`author`** | Who wrote it |
| **`in_reply_to_post_id`**, **`in_reply_to_handle`**, **`conversation_id`** | What it answers |
| **`media`**, **`hashtags`**, **`mentions`**, **`urls`**, **`quoted_post`**, **`reposted_post`** | Attachments and entities |
| **`input_post_id`** | The tweet from your list this row belongs to |
| **`kind`** | `reply` or `quote` |

A reply:

```json
{
  "id": "2111020503045648480",
  "url": "https://x.com/BanksiaPlums/status/2111020503045648480",
  "text": "@elonmusk So…just pointless space rubbish. Littering space for a narcissist’s ego.",
  "lang": "en",
  "source": "Twitter for iPhone",
  "created_at": "2026-10-16T09:04:43.000Z",
  "like_count": 0,
  "reply_count": 0,
  "repost_count": 0,
  "quote_count": 0,
  "view_count": 1,
  "bookmark_count": 0,
  "is_reply": true,
  "in_reply_to_post_id": "2110947164512038931",
  "in_reply_to_user_id": "44196397",
  "in_reply_to_handle": "elonmusk",
  "conversation_id": "2110947164512038931",
  "is_pinned": false,
  "hashtags": [],
  "author_id": "1387519564729266176",
  "author_handle": "BanksiaPlums",
  "author_name": "Banksia Plums",
  "author_followers_count": 1947,
  "author_is_blue_verified": false,
  "input_post_id": "2110947164512038931",
  "kind": "reply"
}
```

A quote of the same tweet:

```json
{
  "id": "2111015199251566852",
  "url": "https://x.com/Z_XSophie/status/2111015199251566852",
  "text": "In 2018 he put a Roadster on a rocket. Last night Tesla put a rocket in a Roadster. 🚀",
  "lang": "en",
  "source": "Twitter for iPhone",
  "created_at": "2026-10-16T08:43:38.000Z",
  "like_count": 10,
  "reply_count": 0,
  "repost_count": 1,
  "quote_count": 0,
  "view_count": 133,
  "bookmark_count": 0,
  "is_reply": false,
  "in_reply_to_post_id": null,
  "in_reply_to_user_id": null,
  "in_reply_to_handle": null,
  "conversation_id": "2111015199251566852",
  "is_pinned": null,
  "hashtags": [],
  "author_id": "1445096722515087363",
  "author_handle": "Z_XSophie",
  "author_name": "SophieZX",
  "author_followers_count": 8111,
  "author_is_blue_verified": true,
  "input_post_id": "2110947164512038931",
  "kind": "quote"
}
```

Nested fields are cut from these examples for length.

### Pricing

You pay for each row saved. A row that is skipped is never charged.

| Plan | Per 1,000 rows |
|---|---|
| Free | $2.00 |
| Bronze | $1.69 |
| Silver | $1.38 |
| Gold and above | $1.08 |

Each run also carries a $0.00005 start charge. The Free plan covers the first 50 rows you save with this Actor; after that you need a paid plan.

### Questions

**Is the original tweet in the dataset?**
No. Only the replies and, with `includeQuotes`, the quotes. If you need the tweet itself, the [Twitter Scraper](https://apify.com/toolzerhub/twitter-scraper) finds it with a `from:` search.

**What is the difference between a reply and a quote?**
A reply sits under the tweet. A quote is a separate tweet on the author's own timeline that embeds the original. They are different lists on X, so they arrive as separate batches: replies first, then quotes for each tweet.

**Why do I get fewer replies than the tweet's `reply_count`?**
The counter includes replies X does not list. The run saves what X lists, and ends when it stops returning pages or returns an empty one.

**Which sort should I use?**
`relevance` for a quick read on sentiment, since X puts what it thinks matters first. `latest` for monitoring, so you can pick up where the last run ended by timestamp. `likes` to find the replies that landed.

**Does `maxItems` apply to each tweet?**
To the whole run, tweets taken in the order listed. For an even spread, run one tweet per run or set a cap that fits the busiest one.

**What if a tweet link is deleted or wrong?**
A malformed link is skipped before any lookup. A deleted tweet returns no rows, so nothing is charged. Both show up in the log, and the other tweets still run.

### Related Actors

| Actor | Use it when |
|---|---|
| [Twitter Tweets Scraper](https://apify.com/toolzerhub/twitter-tweets-scraper) | You want the tweets themselves from an account |
| [Twitter Scraper](https://apify.com/toolzerhub/twitter-scraper) | You want to find tweets about a topic before reading their replies |
| [Twitter Profile Scraper](https://apify.com/toolzerhub/twitter-profile-scraper) | You want the profile behind a replying account |

### Support

Questions, bugs, or feature requests: **contact@toolzerhub.com**

Browse the rest: [apify.com/toolzerhub](https://apify.com/toolzerhub)

# Actor input Schema

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

One or more posts. A post link (`https://x.com/elonmusk/status/2110947164512038931`) or just the numeric ID works, and one list can mix them.

## `replySort` (type: `string`):

`Relevance` is the order X shows by default. `Latest` is newest first. `Likes` puts the most liked replies first.

## `includeQuotes` (type: `boolean`):

After the replies, also save the posts that quote each post.

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

Most rows to save in this run, across everything in the list. Set 0 for no limit.

## Actor input object example

```json
{
  "postUrls": [
    "https://x.com/elonmusk/status/2110947164512038931"
  ],
  "replySort": "relevance",
  "includeQuotes": false,
  "maxItems": 50
}
```

# Actor output Schema

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

Every record collected during this run

# 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 = {
    "postUrls": [
        "https://x.com/elonmusk/status/2110947164512038931"
    ],
    "maxItems": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("toolzerhub/twitter-comments-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 = {
    "postUrls": ["https://x.com/elonmusk/status/2110947164512038931"],
    "maxItems": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("toolzerhub/twitter-comments-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 '{
  "postUrls": [
    "https://x.com/elonmusk/status/2110947164512038931"
  ],
  "maxItems": 50
}' |
apify call toolzerhub/twitter-comments-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,toolzerhub/twitter-comments-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/ZyRdtXSMHTVgEtJL4/builds/otX2qzEgl97roN2W8/openapi.json
