# Twitter Replies Scraper: every reply under a tweet

Twitter Replies Scraper takes a public tweet and returns the replies underneath it, each carrying the replier’s profile and enough thread context to rebuild the conversation.

[Run this scraper free](https://apify.com/apidojo/twitter-replies-scraper)

[See the three jobs](#jobs)

apidojo/twitter-replies-scraper

**Default replies flow**

**Search flow**

**Tweets**

**Replies returned**

Estimated run cost

$0.00

Free Apify plan: 5 runs a month, 10 items a run. No credit card.

**$0.014** per tweet, default flow

**$0.016** per tweet, search flow

**~40** items free per query, paid plans

**100%** run success, last 30 days

Read on 21 September 2026.

## Which route, and how many tweets?

A tweet is named by URL or by ID, and the two are interchangeable. The choice that changes the bill is which of the two collection routes the run takes, and it is one boolean.

-   `startUrls`

    per tweetpriced by flow

    ~40 items free

    Paste the tweet link. Either the x.com or twitter.com form is accepted.

    `x.com/Nike/status/1981345445986402472`

-   `tweetIds`

    per tweetpriced by flow

    ~40 items free

    The digits at the end of that URL. What to store when tweets come out of a database.

    `1981345445986402472`

-   The switch that is the whole product

    `useSearch`

    $0.014 → $0.01614% for coverage

    Off by default

    Off, the run uses Twitter’s replies endpoint. On, it runs a conversation\_id: search instead, which the listing says can surface replies the endpoint misses.

    `useSearch: true`

-   `maxItems`

    ÷ $0.0004budget to cap

    First thing to check

    The ceiling. Leave it empty for everything the tweet has, which on a viral thread is a lot.

    `500`

The roughly forty free items are a paid-plan allowance and apply to either flow. On the free plan there are no query or item charges at all, because demo mode caps a run at ten items.

**Apify actor:** apidojo/twitter-replies-scraper

**Inputs:** startUrls · tweetIds · useSearch · maxItems · customMapFunction

**Returns:** One record per reply, with the replier’s profile and thread context

**Two flows:** The replies endpoint at $0.014, or a conversation_id: search at $0.016

**Free allowance:** Roughly the first 40 items per query, on paid plans, on either flow

**Engagement:** Includes viewCount, which not every scraper in this family returns

**Login or proxy:** Neither. Public tweets only

**Reliability:** 100% of 4,193 runs succeeded in the last 30 days

## One tweet, many tweets, or a second pass

Three ways to run it: read one conversation, batch a set of tweets, or go back over a thread that came back thinner than it looked on X.

**01 One conversation $0.014 / tweet · ~40 free**

**02 A set of tweets One query per tweet**

**03 Go back deeper $0.016 / tweet · ~40 free**

### How do you scrape the replies to a tweet?

Put the tweet URL in startUrls, or its ID in tweetIds, and leave useSearch off. The tweet costs $0.014 with roughly 40 replies inside it, then $0.0004 each. Five hundred replies cost $0.20.

Input

```
{
  "startUrls": [
    "https://x.com/Nike/status/1981345445986402472"
  ],
  "useSearch": false,
  "maxItems": 500
}
```

$0.014 + 460 × $0.0004 \= **$0.20**

What comes back

The **reply record**, Six engagement counters including views, plus who the reply answered.

```
{
  "type": "reply",
  "id": "1981347133442888040",
  "url": "https://x.com/Trueblue1123134/status/1981347133442888040",
  "text": "@Nike W",
  "fullText": "@Nike W",
  "source": "Twitter for Android",
  "likeCount": 1,
  "viewCount": 147,
  "createdAt": "Thu Oct 23 13:09:02 +0000 2025",
  "lang": "und",
  "isReply": true,
  "inReplyToUsername": "Nike"
}
```

A tweet with no replies wastes the run

The listing asks that the tweet exist, be public, and actually have replies, a tweet with none returns an empty dataset and burns run time. Protected accounts and deleted or invalid IDs are not supported at all, so check the tweet on x.com before a scheduled job depends on it.

### How do you scrape replies across several tweets at once?

List the IDs in tweetIds. Each tweet is its own query with its own free allowance, so ten tweets on the default flow cost $0.14 in query fees and bring roughly 400 replies inside them.

Input

```
{
  "tweetIds": [
    "1981345445986402472", "1970912731290058851"
  ],
  "useSearch": false,
  "maxItems": 1000
}
```

10 × $0.014 + 600 × $0.0004 \= **$0.38**

What comes back

The **reply record**, conversationId tells you which tweet each reply belongs to across the batch.

```
{
  "conversationId": "1981345445986402472",
  "inReplyToId": "1981345445986402472",
  "inReplyToUserId": "415859364",
  "isRetweet": false,
  "isQuote": false,
  "author": {
    "userName": "Trueblue1123134",
    "followers": 14,
    "isBlueVerified": false,
    "statusesCount": 55
  }
}
```

URLs and IDs mix freely in one run

Both input fields are read, so a batch can be half links and half IDs without splitting it into two runs. Each entry is charged as its own query either way.

### What if the replies come back thinner than the tweet shows?

Turn useSearch on. Instead of the replies endpoint the actor runs a conversation\_id: search, which the listing says can surface replies the endpoint misses, especially on very large or old threads. It costs $0.016 a tweet rather than $0.014.

Input

```
{
  "tweetIds": ["1981345445986402472"],
  "useSearch": true,
  "maxItems": 500
}
```

$0.016 + 460 × $0.0004 \= **$0.20**

What comes back

The **reply record**, The same shape. Only the route to it changes, not what comes back per item.

```
{
  "entities": {
    "user_mentions": [
      {
        "id_str": "415859364",
        "name": "Nike",
        "screen_name": "Nike"
      }
    ]
  },
  "bookmarkCount": 0,
  "quoteCount": 0,
  "media": []
}
```

Check maxItems before you pay the premium

The listing’s troubleshooting puts maxItems first for a reason: a low ceiling stops a run early and looks exactly like a thin thread. Raise it, re-run on the default flow, and only then spend the extra two tenths of a cent on the search route.

## A reply, and what it answers

One shape per record. What sets it apart from a plain tweet is the thread block: four fields naming the conversation and the account being replied to, which is what makes the output rebuildable into a discussion.

-   7

    The reply

    Always present

    -   id, url, twitterUrl
    -   text, fullText
    -   createdAt
    -   lang
    -   source, the posting client
-   6

    Engagement

    Includes views

    -   likeCount, retweetCount
    -   replyCount, quoteCount
    -   viewCount
    -   bookmarkCount
-   4

    Thread context

    What makes it a reply

    -   conversationId
    -   inReplyToId
    -   inReplyToUserId
    -   inReplyToUsername
-   9

    Who replied

    author, on every record

    -   userName, id, name
    -   followers, following
    -   statusesCount, mediaCount
    -   favouritesCount
    -   isVerified, isBlueVerified
    -   createdAt, account age

**type:** Always "reply" on these records

**id · url · twitterUrl:** The reply’s ID and both link forms

**text · fullText:** The reply body, and its untruncated form

**source:** Posting client, e.g. "Twitter for Android"

**createdAt:** X’s own date string format

**lang:** Language X detected. "und" where it could not tell

**likeCount · retweetCount:** Engagement on the reply itself

**replyCount · quoteCount:** Replies to the reply, and quote-tweets of it

**viewCount:** Impressions. Present here, absent on Twitter Scraper Unlimited

**bookmarkCount:** Saves on the reply

**conversationId:** The thread. Group on it to rebuild the discussion

**inReplyToId:** The exact tweet this answers, which may be another reply

**inReplyToUserId · inReplyToUsername:** Who is being answered, by ID and handle

**author.followers · statusesCount:** The replier’s reach and posting volume

**author.createdAt:** Account age. The cheapest signal that a replier is new

**entities.user_mentions:** Accounts mentioned, each with id_str, name and screen_name

inReplyToId and conversationId are not the same field. The first names the tweet this record answers, which is often another reply; the second names the tweet that started the whole thread. Together they give you the tree rather than a flat list.

## What the listing asks of you

Five conditions, four of them stated outright in the listing’s own usage note and troubleshooting.

-   01

    The tweet must be public, real, and have replies

    Deleted, protected and invalid IDs are not supported. A tweet with no replies returns an empty dataset and wastes the run, so the listing asks you to check on x.com first.

-   02

    Check maxItems before blaming the flow

    A ceiling set too low stops a run early and looks identical to a thread that came back thin. It is the first thing the listing’s troubleshooting tells you to look at.

-   03

    The search flow is the second attempt, not the default

    useSearch runs a conversation\_id: search rather than the replies endpoint. The listing recommends it when the default returns fewer results than expected, particularly on very large or old threads.

-   04

    The free allowance is a paid-plan benefit

    Roughly the first 40 items per query are free on either flow for paid plans. Free accounts are in demo mode instead: no query or item charges, 10 items a run, 5 runs a month.

-   05

    The Console preview is not the dataset

    It shows only a subset of fields. Download from the Storage tab, or open the dataset in a new tab, before concluding that fields are missing.

Metrics are read at the moment of scraping and match what X showed then.

## What the two flows cost

Every tweet is one query, $0.014 on the default flow, $0.016 on the search flow, with roughly 40 items inside it, then $0.0004 a reply. The gap between the flows is two tenths of a cent per tweet, which matters only at batch scale.

| Run | Method | Calculation | Cost |
| --- | --- | --- | --- |
| 40 replies | 1 tweet · default | $0.014 | $0.014 |
| 40 replies | 1 tweet · search | $0.016 | $0.016 |
| 500 replies | 1 tweet · default | $0.014 + 460 × $0.0004 | $0.20 |
| 500 replies | 1 tweet · search | $0.016 + 460 × $0.0004 | $0.20 |
| 1,000 replies | 10 tweets · default | 10 × $0.014 + 600 × $0.0004 | $0.38 |
| 1,000 replies | 10 tweets · search | 10 × $0.016 + 600 × $0.0004 | $0.40 |
| 10,000 replies | 50 tweets · default | 50 × $0.014 + 8,000 × $0.0004 | $3.90 |

Computed from the three charge events the Apify Store API reports. On a single tweet the two flows round to the same figure past a few hundred replies; across fifty tweets the search flow adds a tenth of a dollar in query fees, which is the price of not missing a conversation.

## Who reads the replies rather than the post?

Five kinds of work live underneath the tweet rather than in it: social listening, sentiment analysis, competitive intelligence, lead generation and community management.

-   Brand monitoring

    One conversation, on announcements

    Read what people said back to a brand post, where the reaction is the thing being measured

    $0.20 per 500 replies

-   Sentiment analysis

    A set of tweets, batched

    Build labelled reply corpora across a campaign’s posts, with viewCount as an exposure weight

    $0.38 per 1,000 replies

-   Competitive intelligence

    One conversation, on a rival’s launch

    See what a competitor’s audience complains about in public, which their own feed will not tell you

    $0.014 per thread at 40 replies

-   Lead generation

    A set of tweets, then filter authors

    Find people actively discussing a problem, with follower counts and account age attached to each

    $3.90 per 10,000 replies

-   Community managers

    Go back deeper, on big threads

    Make sure nothing was missed on a thread large enough for the default flow to come back short

    $0.016 per re-check

## Calling both flows from code

The actor is apidojo/twitter-replies-scraper. The pattern worth writing once is the fallback: run the cheap flow, and only re-run with useSearch when the result looks thin against the tweet’s own replyCount.

**Python**

**JavaScript**

**cURL**

```
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
ACTOR = "apidojo/twitter-replies-scraper"

def replies(tweet_id, use_search=False, cap=500):
    run = client.actor(ACTOR).call(run_input={
        "tweetIds": [tweet_id],
        "useSearch": use_search,
        "maxItems": cap,
    })
    return list(client.dataset(run.default_dataset_id).iterate_items())

rows = replies("1981345445986402472")

# Thin result on a big thread is what the search flow is for.
if len(rows) < 40:
    rows = replies("1981345445986402472", use_search=True)

for r in rows:
    print(r["author"]["userName"], r["viewCount"], r["inReplyToUsername"], r["text"][:50])
```

```
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

const run = await client.actor('apidojo/twitter-replies-scraper').call({
  tweetIds: ['1981345445986402472'],
  useSearch: false,
  maxItems: 1000,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();

// inReplyToId is the parent, conversationId is the root: that is a tree.
const children = Object.groupBy(items, (r) => r.inReplyToId);
const direct = children[items[0]?.conversationId] ?? [];
console.log(direct.length, 'direct replies of', items.length, 'in the thread');
```

```
curl -X POST \
  "https://api.apify.com/v2/acts/apidojo~twitter-replies-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"tweetIds":["1981345445986402472"],"useSearch":true,"maxItems":500}'
```

Exports are JSON, CSV or Excel from the Storage tab, or straight off the API. Remember the Console preview shows a subset of fields, a missing field there is usually present in the downloaded dataset.

## Twitter Replies Scraper FAQ

### What is the difference between the two flows?

The default uses Twitter’s replies endpoint at $0.014 a tweet. With useSearch on, the actor runs a conversation\_id: search instead at $0.016, which the listing says can surface replies the endpoint misses on very large or old threads.

### How much does it cost to scrape replies from a tweet?

One tweet is $0.014 on the default flow or $0.016 with useSearch, and roughly the first 40 replies are included on a paid plan. Five hundred replies come to about $0.20 either way.

### Why did I get fewer replies than the tweet shows?

Check maxItems first, a low ceiling stops the run early. If it is not that, turn useSearch on and try the broader conversation\_id: flow, which is what the listing recommends for large threads.

### Can I mix tweet URLs and tweet IDs in one run?

Yes. startUrls and tweetIds are both read in the same run, and each entry is charged as its own query whichever field it came from.

### Can I rebuild the whole conversation tree?

Yes. conversationId names the tweet that started the thread and inReplyToId names the specific tweet each record answers, so grouping on inReplyToId gives you the branches rather than a flat list.

### Do replies include the replier’s profile?

Every record nests an author object with handle, display name, follower and following counts, total posts, verification flags and the account’s creation date.

### Can I scrape replies on a protected account’s tweet?

No. Only public tweets are accessible, and deleted or invalid IDs are not supported either.

### Are some fields missing from my results?

The Apify Console preview only renders a subset. Download the dataset from the Storage tab, or open it in a new tab, to see every field.

## Where Twitter Replies Scraper fits

[Parent scraper Twitter Scraper All six Twitter scrapers, what each charges and where each stops. Two others can reach replies as part of a wider job; this is the one that does nothing else, and the only one that offers a second route when the first comes back short.](/scrapers/twitter-scraper/)

Sibling scrapers

-   [Twitter Scraper Unlimited](/scrapers/twitter-scraper-lite/)
-   [Twitter Profile Scraper](/scrapers/twitter-profile-scraper/)
-   [Twitter User Scraper](/scrapers/twitter-user-scraper/)

Guides

-   Rebuilding an X conversation tree from replies*Coming soon*
-   When the replies endpoint under-returns, and what to do*Coming soon*
-   Account age as a bot signal in reply data*Coming soon*

## Open one thread

A cent and a half, with the first forty replies inside it.

`tweetIds: ["1981345445986402472"] · useSearch: false`

[Run this scraper free](https://apify.com/apidojo/twitter-replies-scraper)

Apidojo is not affiliated with X Corp.

## Guides for this scraper

-   [Scraping X (Twitter) data: guides by task Turning an X search query into structured data: which actor fits each job, what a run costs, and the limits that decide how you batch it.](/blog/twitter-scraping/)
-   [How to rebuild an X conversation tree from replies Replies arrive as a flat list. Two fields, conversationId and inReplyToId, are what turn that list back into the threaded conversation you saw on X.](/blog/twitter-scraping/x-reply-tree/)
-   [Reading account age in X reply data Every reply carries the responder's account creation date, follower counts and post history. Here is what those fields can and cannot tell you.](/blog/twitter-scraping/x-replier-account-age/)
-   [When the X replies endpoint under-returns A thread that looks busy on X can come back thin from a scrape. Here is how to tell a quiet conversation from a short run, and what the second flow fixes.](/blog/twitter-scraping/x-replies-vs-search-flow/)
