Twitter X Tweets Scraper & Post Replies
Pricing
from $5.99 / 1,000 results
Twitter X Tweets Scraper & Post Replies
Twitter X Tweets Scraper & Post Replies: Extract tweets, replies, authors, timestamps, likes, reposts, views, hashtags, mentions, and engagement data. Monitor conversations, analyze audience reactions, research trends, track competitors, and build structured datasets from X.
Pricing
from $5.99 / 1,000 results
Rating
0.0
(0)
Developer
Scrapier
Maintained by CommunityActor stats
0
Bookmarked
4
Total users
0
Monthly active users
2 days ago
Last modified
Categories
Share
Twitter X Tweets Scraper Scraper & Post Replies
An X (Twitter) scraper that returns public posts and the replies people wrote underneath them. One post is still one dataset row; the conversation rides on that row as a post_replies array, so a spreadsheet built on the base X posts scraper keeps working and simply gains columns.
It is a strict superset of Twitter X Tweets Scraper Scraper: every input that actor accepts still works with the same meaning, and every output field it emits is still present with the same value, produced by the same code.
What it does
- Scrapes X profile timelines, numeric user IDs and single post URLs — post text (long-form posts untruncated), likes, replies, reposts, quotes, bookmarks, views, language, media, hashtags, mentions, quoted posts, poll results, link cards and the author's profile stats.
- Opens each collected post's conversation through X's
TweetDetailGraphQL surface and attaches the replies to that post's row. - Per reply: the text, the author's handle / display name / user id / follower count / bio / avatar / blue-verified flag, the reply's own likes, replies, reposts and views, any attached photos, the id of the post or reply it answers, and two flags — whether the replier is the post's own author continuing a thread, and whether the reply answers the post directly.
- Screens the conversation by replier follower count — the audience-size filter that a purchasable blue badge no longer provides.
- Lets you choose which ranking X serves (Likes / Relevance / Recency) or union all three in one deep sweep — which matters, because the ranking changed unique-reply recovery by 6.7x on one measured post and no ranking wins on every post.
- Reports reply completeness honestly:
replies_declared(X's own count, never overwritten),replies_returned,replies_recovery_ratio,replies_truncated,replies_dropped_by_filter,reply_pages_fetchedandreply_fetch_status.
Which features need the X session cookie
| Feature | Session needed? |
|---|---|
| Profile timelines, single post URLs, media, polls, quoted posts, repost originals | No — keyless, guest token |
collectPostReplies — the replies under each post (TweetDetail) | Yes |
replyRanking, deepReplySweep, minReplierFollowers, onlyRepliedPosts | Yes (they all shape the reply fetch) |
includeReplies — the profile's own Posts-and-replies tab (UserTweetsAndReplies) | Yes |
Pressing Start with the stock settings runs the keyless post scrape: collectPostReplies is off by default, because the session can only reach the actor through two isSecret fields and Apify forbids a default or prefill on those. Switch it on after pasting the cookies.
Measured 2026-08-03: TweetDetail returns HTTP 404 with a 0-byte body to a logged-out caller on both GET and POST. There is no keyless way to read replies. With reply collection on and no session, this actor fails immediately and names TweetDetail — it never returns posts with empty reply arrays, because that reads as a room full of quiet accounts rather than a missing login.
Paste auth_token and ct0 from an x.com browser session (DevTools → Application → Cookies → x.com). Both fields are isSecret, are stored encrypted, are sent only to api.x.com, and are scrubbed out of every log line and exception. Nothing credential-shaped is baked into this actor's source.
Input
| Field | Type | Default | What it does |
|---|---|---|---|
startUrls | array | ["https://x.com/NASA/status/2082511887757881648"] | Profiles, @handles, numeric user IDs or single post URLs, one per line |
maxTweets | integer | 10 | Posts per PROFILE (1–1000). Post URLs ignore it |
sortOrder | enum | recent | Re-orders the posts collected in this run |
collectPostReplies | boolean | false | Open each post's conversation and attach the replies. Needs the X session, so it is off by default and the stock run is the keyless post scrape |
maxRepliesPerPost | integer | 20 | Replies kept per post (1–200) |
replyRanking | enum | Likes | Likes / Relevance / Recency |
deepReplySweep | boolean | false | Sweep all three rankings and merge by reply id |
minReplierFollowers | integer | 0 | Keep only replies whose author meets this follower floor |
onlyRepliedPosts | boolean | false | Drop posts whose conversation returned nothing |
includeReplies | boolean | false | Also collect the profile's own replies as posts |
auth_token | secret string | — | X session cookie |
ct0 | secret string | — | X CSRF cookie from the same session |
proxyConfiguration | object | off | Optional Apify Proxy |
Output
One row per post. All 40 base fields, plus 10 reply fields:
| Field | Type | Meaning |
|---|---|---|
has_replies | boolean | The conversation served at least one reply, measured BEFORE the follower floor — so a post whose replies were all filtered out still reads true. null when the conversation was never opened or the sweep was cut short. Use replies_returned > 0 for “does this row carry replies” |
replies_declared | integer | X's own reply count for the post — identical to replies, never overwritten |
replies_returned | integer | How many reply objects are in post_replies, after the cap and the follower floor |
replies_recovery_ratio | number | replies_returned / replies_declared. null when X declares 0, or when the sweep was cut short before anything was collected. Can exceed 1 |
replies_truncated | boolean | More replies existed than were returned |
replies_dropped_by_filter | integer | Replies removed by minReplierFollowers |
reply_pages_fetched | integer | Conversation pages requested for this post |
reply_ranking_used | string | Likes, Relevance, Recency, or Likes+Relevance+Recency on a deep sweep |
reply_fetch_status | string | complete, capped, rate_limited, fetch_failed or not_attempted |
post_replies | array | The replies |
Each post_replies[] entry: reply_id, text, date_posted, url, username, name, user_id, followers, is_blue_verified, biography, profile_image_link, likes, replies, reposts, views, photos (a list), replied_to_post_id, is_reply_to_author, is_direct_reply.
Targets that produce nothing get an uncharged accounting row with type: "error", a typed errorReason (the base's ten reasons plus all_posts_filtered_out) and a plain-English message. A run that collects zero posts exits FAILED with a terminal status message.
Dataset views: Posts & reply recovery (default), The conversation, Media & entities, Reposts, quotes & pin state, Polls & link cards, Author profile, Skipped targets.
is_pinned is a profile-level fact and is null on any post fetched by its own URL, so it lives in the Reposts, quotes & pin state view rather than in the default table.
For the same reason has_replies, replies_returned, replies_recovery_ratio and replies_truncated live in The conversation view: they are null on every row of a keyless run, which is the stock configuration, and a permanently empty column in the first table a buyer sees is worse than one extra click. replies_declared stays in the default table because X publishes it on every post whether or not the conversation was opened.
Honest limits — measured 2026-08-03
- "Every reply" is not deliverable, and no ranking is best.
TweetDetailplateaus at a few hundred top-level replies per post regardless of how many the post declares, and which ranking goes deepest is post-dependent. Measured in-container 2026-08-03 on post2082511887757881648(X declares 337 replies), pagination run to natural termination: Relevance 228 unique replies over 7 requests, Likes 182 over 12, Recency 34 over 8 — a 6.7x spread on the same post. On a different, larger post a direct probe of the surface gave the opposite order (Likes 581, Recency 503, Relevance 375; union 822). Reply sets drift between runs, so these are magnitudes rather than constants.replies_declaredandreplies_returnedboth ship so the gap is always visible; X's count also includes replies from blocked, protected and deleted accounts the conversation view never serves. replies_recovery_ratiocan exceed 1. X's ownreply_countlags the conversation view on quiet posts — measured in-container, one post declared 1 reply and the conversation served 4, and one declared 0 and served 5. Both numbers are reported exactly as X gave them; neither is corrected to make the ratio look tidy.- The conversation view is mostly, not entirely, flat. Measured in-container over 133 replies from 14 posts: 98 answered the post directly, 29 answered another reply or an earlier post in the same self-thread, and 6 carried no in-reply-to id at all.
replied_to_post_idandis_direct_replyboth ship because both vary. There is nodepthcolumn: X inlines a branch without saying how deep it is, and a true depth needs one extra request per parent reply — a different product. Joinreplied_to_post_idagainstreply_idto rebuild the branch yourself. - Empty conversation modules are not rows. X streams 7–8 modules per post that carry no tweet at all — withheld or deleted replies. They are never emitted and never counted toward any total.
- Hidden replies stay hidden. X lets an author hide replies; they live behind a surface this actor does not open. An absence of criticism in the output is not evidence none was written.
- Rate limit.
TweetDetailis 150 requests per 15 minutes, tied to your X session — a proxy does not raise it. Roughly one request per 20 replies. A 429 is handled loudly: the sweep stops, keeps whatever it already collected, and reportsreply_fetch_status: "rate_limited"on that post withhas_replies: nullandreplies_recovery_ratio: null— neverfalseand never0, because a conversation nobody finished reading is unknown, not empty. minReplierFollowersdeletes real people. Small accounts are where genuine customer complaints live, which is why the default is 0 and why every removal is counted inreplies_dropped_by_filter.- Reply order is X's, not yours.
post_repliespreserves the order X served under the ranking you chose. It is not chronological unless you pickRecency. - Per-post geolocation is not available. X returns
legacy.place,geoandcoordinatesas null on every post measured, so no location column ships. - Nothing is scored or summarised. No sentiment, no tone, no toxicity. The counts are row counts and presence checks over text X served.
- Reply text is public writing by identifiable people and routinely contains more personal detail than the post it answers. GDPR, CCPA and equivalent rules apply to storing and processing it.
- One snapshot. Everything is read once, at fetch time, and reported as read. Nothing is compared against a previous run.
Keywords
X reply scraper, Twitter replies scraper, Twitter comments scraper, X conversation scraper, tweet replies API, X post replies export, Twitter thread scraper, X engagement scraper, Twitter audience research, X social listening, tweet scraper no-code, Twitter data export, X community management, reply sentiment source data, Twitter brand monitoring.