Twitter (X.com) Tweets & Profiles Scraper avatar

Twitter (X.com) Tweets & Profiles Scraper

Pricing

from $4.99 / 1,000 results

Go to Apify Store
Twitter (X.com) Tweets & Profiles Scraper

Twitter (X.com) Tweets & Profiles Scraper

Scrape public Twitter X profiles with tweets, bios, followers, links, and engagement data. This actor captures structured profile insights at scale, supports keyword filtering, and exports clean JSON or CSV for research, analysis, and automation workflows.

Pricing

from $4.99 / 1,000 results

Rating

0.0

(0)

Developer

API Empire

API Empire

Maintained by Community

Actor stats

0

Bookmarked

16

Total users

0

Monthly active users

a day ago

Last modified

Share

X (Twitter) Scraper — Extract Posts, Replies & Quote Posts as JSON

This X (Twitter) scraper pulls a profile's timeline and then walks every post into its own conversation: replies and quote posts come back as their own child rows, linked to the parent post by parentId, replyDepth, and per-thread roll-up counts. Every row — post, reply, or quote — is typed, normalized JSON with the same column set, so it drops straight into a pipeline, a spreadsheet, or an LLM context window with no HTML and no selectors to write. Read on for exactly which fields each row type carries, what X requires before it hands over a reply or a quote post, and where the platform's own caps sit.


🧭 What is X (Twitter) User Profile & Tweets Scraper + Reply Threads?

X (Twitter) User Profile & Tweets Scraper + Reply Threads is an Apify Actor that scrapes public X profile timelines and turns each post into its full conversation. One run returns three connected entity types — posts, replies, and quote posts — each carrying the same base columns plus a nested author profile. Profile timelines run fully logged out over X's guest-token GraphQL surface; replies, quote posts, and keyword search need a customer-supplied X session (an auth_token + ct0 cookie pair), because X answers those three surfaces with an empty HTTP 404 to anonymous clients.

  • 🧵 Scrape a profile's posts, sorted newest, oldest, or most-liked
  • 💬 Walk every post into its reply thread, up to 3 levels deep
  • 🔁 Collect the quote posts that reference each post
  • 👤 Attach full author profile data — bio, follower counts, join date, verification — to every row
  • 📦 Export the dataset as JSON, CSV, Excel, or any format Apify's dataset API supports

📊 What data does X (Twitter) User Profile & Tweets Scraper + Reply Threads collect?

A single run returns four kinds of data, all in one dataset: the profile's own posts, the replies under each post, the quote posts that reference each post, and the author profile nested on every row.

Data TypeKey FieldsJSON Field Names
Posts (rowType: "tweet")Text, engagement counts, media, links, per-thread roll-up statstext, likes, retweets, quotes, views, media, links, repliesClaimed, repliesCollected, replyRecoveryRatio
Replies (rowType: "reply")Reply text, parent link, depth, in-reply-to targettext, parentId, replyDepth, inReplyToId, inReplyToUsername
Quote posts (rowType: "quote")The quoting post's own text and engagement, parent linktext, parentId, isQuote, likes, retweets
Author profile (nested on every row)Bio, location, follower/following counts, verificationuser.description, user.totalFollowers, user.totalFollowing, user.verified, user.joinDate

Need more X (Twitter) data?

If your workflow is really about who reposted or quoted a post rather than the conversation underneath it, the same account also publishes Twitter X Tweets Scraper Scraper - Repost and Quote, which opens every repost and quote back to the original post's own engagement counts and the original author's profile — a narrower, cheaper tool when reply threads aren't what you need.


⚔️ How does X (Twitter) User Profile & Tweets Scraper + Reply Threads differ from the official X API?

The official X API requires a developer account, app credentials, and metered billing before you get a single row back; this Actor runs from a profile URL with no developer account needed for post data.

FeatureOfficial X APIThis Actor
Access setupSign up at console.x.com, create an app, buy credits (docs.x.com, checked 2026-08-04)Paste a startUrls entry and run — no developer account for post data
PricingPay-per-use: $0.005 per post read, $0.015–$0.200 per post created, capped at 2,000,000 reads per monthly billing cycle (docs.x.com, checked 2026-08-04)Apify's per-result pricing on the Actor's own Store page — no separate per-post metering to track
Read rate limits3,500 tweet reads / 15 min and 450 search requests / 15 min per app (docs.x.com, checked 2026-08-04)Bound by the same X-side limits the Actor reads from x-rate-limit-remaining; backs off automatically on HTTP 429 instead of hard-failing
Reply/conversation coverageConversation lookups go through the same metered search endpoints as everything elseWalks each post into a full reply tree up to 3 levels deep, with recovery stats, in the same run
Output shapeRaw GraphQL/REST JSON keyed to X's own schema; stitching a post to its replies and quotes is your jobOne dataset, three row types already joined by parentId
Setup timeDeveloper account approval plus (for legacy tiers) a subscription starting at $200/month (docs.x.com, checked 2026-08-04)Runs immediately; only the reply/quote/search surfaces need a copied session cookie pair

The official API is the right call for real-time, high-volume programmatic access under a predictable per-request budget with formal API terms attached. This Actor fits one-off or scheduled dataset pulls where you want posts, replies, and quote posts pre-joined into one JSON row without opening a developer account or tracking credits.


🎯 Why do developers and teams scrape X (Twitter)?

🤖 For AI engineers and agent builders

Reply threads are exactly the kind of unstructured signal RAG pipelines want structured. Pull a brand's or a topic's posts with scrapeReplyThreads on, index text and fullTextLongForm per row into a vector store, and use parentId / replyDepth to keep the conversation tree intact for an agent that needs to reason about who said what to whom. Because every row is typed JSON with stable field names, there's no HTML to strip before it reaches the model.

📣 For marketers and brand teams

Point startUrls at a competitor's handle, set includeQuoteTweets on, and read quoteTweetsCollected and the nested user block on each quoting account to see who is amplifying a competitor's launch post and how large their following is — without opening X's own login-walled search UI by hand.

🔬 For researchers and analysts

Public conversation data — who replies to whom, at what depth, with what engagement — is the raw material for discourse and network research. replyRecoveryRatio reports what fraction of a post's claimed replies were actually recoverable, so a study can state its coverage honestly instead of treating a partial pull as complete. Scope is limited to what X serves publicly to the session you supply.

🛠️ For developers building data products

Because posts, replies, and quote posts share one column set, a scheduled run (Apify schedule or webhook) can feed a downstream table or dashboard without a translation layer between row types. threadStatus and quoteStatus on each post row tell your pipeline exactly why a given post's conversation is thin, instead of leaving you to guess.


🚀 How to scrape X (Twitter) (step by step)

  1. Open X (Twitter) User Profile & Tweets Scraper + Reply Threads on its Apify Store listing and click Try for free (or Run, if you already have it saved).
  2. Provide the required input — startUrls, an array of profile URLs, @handles, bare handles, or numeric user IDs. This is the only required field.
  3. Set the entity scope: leave scrapeReplyThreads and includeQuoteTweets on for the full conversation walk, or turn them off for post-only runs; adjust maxTweets, maxRepliesPerTweet, and maxQuoteTweetsPerTweet to the volume you want.
  4. Start the run from the Apify Console, or trigger it programmatically with apify_client, an Apify schedule, or a webhook.
  5. Download the results as JSON, CSV, Excel, or any format the Apify dataset export supports, or stream them via the API while the run is still going.

What to do when X (Twitter) changes its structure

The Actor re-discovers X's current GraphQL query IDs live from X's own JS bundle at the start of each run instead of hard-coding them, and it parses X's "features cannot be null" responses to add newly required feature flags automatically. Output field names and types stay stable on your end, so downstream integrations keep working without a rewrite. No specific turnaround time is promised for platform changes outside this self-healing.


🔄 What changed in X (Twitter) scraping recently?

Two things tightened in 2026. On the official API side, X discontinued the free developer tier and made pay-per-use pricing the default for new signups from February 6, 2026, migrating remaining legacy Basic subscribers onto the same metered plan starting June 1, 2026 (per 2026 X API pricing trackers, checked 2026-08-04). On the anti-bot side, X has been reported moving its login wall and rate-limited endpoints onto Cloudflare's Turnstile challenge as of March 2026 (per scrapeops.io, checked 2026-08-04), layering browser fingerprinting on top of the login wall it rolled out across the site in 2023. For DIY scripts, that means credential and fingerprint churn stacked on the wall itself. For this Actor's users, replies, quote posts, and keyword search already assume a login-gated surface — verified live on 2026-08-02, those three answer HTTP 404 with an empty body to logged-out clients — while post-only runs keep working with no session at all, since the guest-token timeline path remains open.


⬇️ Input

startUrls is the only required field; every other parameter has a default.

ParameterRequiredTypeDescriptionExample Value
startUrlsYesarray of stringsProfile URL, @handle, bare handle, numeric user id, or a search phrase/hashtag. Profile targets run logged out; keyword targets are X search and need the session cookies below. Default ["https://x.com/NASA", "@apify"].["https://x.com/NASA", "@apify"]
maxTweetsNointeger (1–100)Timeline posts to keep per target — parents only, replies and quotes have their own caps. Default 10.10
sortOrderNostring, enum newest/oldest/popularOrder applied to fetched posts before the cap is applied. Default "newest"."newest"
withRepliesNobooleanOFF removes posts that are themselves replies written by the scraped profile. Default true.true
includeUserInfoNobooleanAttaches the nested user profile object to post, reply and quote rows. Default true.true
scrapeReplyThreadsNobooleanWalks each post into its conversation; needs the session cookies below. Default true.true
maxRepliesPerTweetNointeger (0–200)Reply rows kept per post. 0 = everything X serves, up to the 200 ceiling. Default 25.25
replyDepthNointeger (1–3)1 direct replies only, 2 also the nested replies X ships inline, 3 one extra request per answered reply. Default 2.2
threadRankingModeNostring, enum relevance/recencyWhich replies X serves first when the cap cuts the thread short. Default "relevance"."relevance"
minRepliesToFetchNointeger (0–100000)Skip posts with fewer replies than this, read from the post's own counter before any request. Default 1.1
followHiddenRepliesNobooleanFollows the "show more replies" cursors X puts behind hidden branches. Default true.true
includeQuoteTweetsNobooleanRuns one X search per post for posts that quoted it. Default true.true
maxQuoteTweetsPerTweetNointeger (0–50)Quote rows kept per post; 0 skips the quote search entirely. Default 10.10
authTokenNostring (secret)auth_token cookie from a logged-in x.com tab. Required for replies, quote posts, and keyword search. No default."a1b2c3..."
ct0Nostring (secret)ct0 cookie (CSRF token) from the same session as authToken. No default."9f3a7c..."
proxyConfigurationNoobjectProxy attached to every outbound request, including guest-token activation and query-id discovery. Default {"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]}.{"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]}

Example input, all parameters shown:

{
"startUrls": ["https://x.com/NASA", "@apify"],
"maxTweets": 10,
"sortOrder": "newest",
"withReplies": true,
"includeUserInfo": true,
"scrapeReplyThreads": true,
"maxRepliesPerTweet": 25,
"replyDepth": 2,
"threadRankingMode": "relevance",
"minRepliesToFetch": 1,
"followHiddenReplies": true,
"includeQuoteTweets": true,
"maxQuoteTweetsPerTweet": 10,
"authToken": "",
"ct0": "",
"proxyConfiguration": {
"useApifyProxy": true,
"apifyProxyGroups": ["RESIDENTIAL"]
}
}

⚠️ Common pitfall: leaving authToken and ct0 empty and still expecting reply, quote, or keyword-search rows. Those three surfaces answer HTTP 404 with an empty body to logged-out clients, so a keyless run silently returns post rows only — every post row carries threadSkippedReason: "auth_required" so you can see why, rather than assuming the post had no replies.


⬆️ Output

Every run pushes typed, normalized JSON rows to one Apify dataset — no HTML, no per-field parsing. Export as JSON, CSV, Excel, or any format the dataset API supports. rowType distinguishes the three shapes below; isChild and parentId link a reply or quote back to its post. If includeUserInfo is off, the user object is omitted from every row rather than being sent as null.

Scraped post (rowType: "tweet")

{
"id": "1948213340098213888",
"url": "https://x.com/NASA/status/1948213340098213888",
"verified": true,
"username": "@NASA",
"fullname": "NASA",
"timestamp": "Fri Jul 31 21:25:11 +0000 2026",
"postedAt": "2026-07-31T21:25:11Z",
"text": "New images from the James Webb Space Telescope reveal...",
"links": ["https://science.nasa.gov/mission/webb"],
"isPinned": false,
"isQuote": false,
"isRetweet": false,
"isReply": false,
"likes": 8421,
"replies": 297,
"retweets": 1520,
"quotes": 63,
"views": 512034,
"user": {
"avatar": "https://pbs.twimg.com/profile_images/example_normal.jpg",
"username": "NASA",
"userFullName": "NASA",
"description": "Explore the universe and discover our home planet.",
"location": "",
"website": "https://www.nasa.gov",
"url": "https://t.co/abc123",
"joinDate": "Wed Dec 19 20:20:32 +0000 2007",
"verified": true,
"verifiedType": "Business",
"totalLikes": 5123,
"totalTweets": 76210,
"totalFollowing": 320,
"totalFollowers": 96500000,
"totalMediaCount": 15340,
"userId": "11348282"
},
"media": [{"type": "photo", "url": "https://pbs.twimg.com/media/example.jpg"}],
"tweetUserId": "11348282",
"retweetedFrom": null,
"originalTweetId": null,
"isPinnedPost": false,
"retweetSource": null,
"rowType": "tweet",
"isChild": false,
"parentId": null,
"parentUrl": null,
"replyDepth": 0,
"conversationId": "1948213340098213888",
"bookmarks": 940,
"lang": "en",
"inReplyToId": null,
"inReplyToUsername": null,
"isLongForm": false,
"fullTextLongForm": null,
"targetInput": "https://x.com/NASA",
"targetType": "username",
"threadFetched": true,
"threadStatus": "ok",
"threadSkippedReason": null,
"repliesClaimed": 297,
"repliesCollected": 25,
"replyRecoveryRatio": 0.0842,
"uniqueReplyAuthors": 24,
"deepestReplyDepth": 2,
"threadPagesFetched": 3,
"promotedRepliesSkipped": 1,
"quoteTweetsCollected": 10,
"quoteStatus": "ok"
}

Scraped reply (rowType: "reply")

Reply rows carry the same base columns as a post row (minus the thread roll-up stats, which live only on the post row they belong to), plus parentId, parentUrl, and replyDepth.

{
"id": "1948214001233456789",
"url": "https://x.com/spacefan42/status/1948214001233456789",
"verified": false,
"username": "@spacefan42",
"fullname": "Space Fan",
"timestamp": "Fri Jul 31 21:40:02 +0000 2026",
"postedAt": "2026-07-31T21:40:02Z",
"text": "@NASA This is incredible, thank you for sharing!",
"links": [],
"isPinned": false,
"isQuote": false,
"isRetweet": false,
"isReply": true,
"likes": 12,
"replies": 1,
"retweets": 0,
"quotes": 0,
"views": 480,
"user": {
"avatar": "https://pbs.twimg.com/profile_images/example2_normal.jpg",
"username": "spacefan42",
"userFullName": "Space Fan",
"description": "Amateur astronomer.",
"location": "Ohio",
"website": null,
"url": null,
"joinDate": "Mon Mar 03 14:02:10 +0000 2014",
"verified": false,
"verifiedType": null,
"totalLikes": 22140,
"totalTweets": 5310,
"totalFollowing": 640,
"totalFollowers": 812,
"totalMediaCount": 210,
"userId": "998877665"
},
"media": [],
"tweetUserId": "998877665",
"retweetedFrom": null,
"originalTweetId": null,
"isPinnedPost": false,
"retweetSource": null,
"rowType": "reply",
"isChild": true,
"parentId": "1948213340098213888",
"parentUrl": "https://x.com/NASA/status/1948213340098213888",
"replyDepth": 1,
"conversationId": "1948213340098213888",
"bookmarks": 0,
"lang": "en",
"inReplyToId": "1948213340098213888",
"inReplyToUsername": "NASA",
"isLongForm": false,
"fullTextLongForm": null,
"targetInput": "https://x.com/NASA",
"targetType": "username"
}

Scraped quote post (rowType: "quote")

Quote rows share the same shape as a reply row, except replyDepth is always null — a quote post lives outside the conversation and isn't a reply.

{
"id": "1948220112233445566",
"url": "https://x.com/newsdesk/status/1948220112233445566",
"verified": true,
"username": "@newsdesk",
"fullname": "News Desk",
"timestamp": "Fri Jul 31 22:05:47 +0000 2026",
"postedAt": "2026-07-31T22:05:47Z",
"text": "NASA just dropped the clearest Webb images yet -- thread below",
"links": ["https://x.com/NASA/status/1948213340098213888"],
"isPinned": false,
"isQuote": true,
"isRetweet": false,
"isReply": false,
"likes": 340,
"replies": 18,
"retweets": 52,
"quotes": 3,
"views": 21500,
"user": {
"avatar": "https://pbs.twimg.com/profile_images/example3_normal.jpg",
"username": "newsdesk",
"userFullName": "News Desk",
"description": "Science and space news.",
"location": "New York, NY",
"website": "https://newsdesk.example.com",
"url": "https://t.co/xyz789",
"joinDate": "Tue Jan 08 09:15:00 +0000 2013",
"verified": true,
"verifiedType": "Business",
"totalLikes": 41230,
"totalTweets": 98211,
"totalFollowing": 210,
"totalFollowers": 154000,
"totalMediaCount": 6210,
"userId": "445566778"
},
"media": [],
"tweetUserId": "445566778",
"retweetedFrom": null,
"originalTweetId": null,
"isPinnedPost": false,
"retweetSource": null,
"rowType": "quote",
"isChild": true,
"parentId": "1948213340098213888",
"parentUrl": "https://x.com/NASA/status/1948213340098213888",
"replyDepth": null,
"conversationId": "1948220112233445566",
"bookmarks": 22,
"lang": "en",
"inReplyToId": null,
"inReplyToUsername": null,
"isLongForm": false,
"fullTextLongForm": null,
"targetInput": "https://x.com/NASA",
"targetType": "username"
}

threadStatus is one of not_requested, skipped, ok, or failed; threadSkippedReason is one of auth_required, below_min_replies, no_replies, rate_limited, fetch_failed, or null; quoteStatus is one of not_requested, auth_required, rate_limited, ok, or failed. Repost rows carry the original post's content and author throughout — retweetedFrom names the account that reposted it, and originalTweetId is the original post's id.


🆚 How does this scraper compare to other X (Twitter) scrapers?

FeatureThis scraperGeneric alternative
Replies as their own dataset rowsrowType: "reply", linked by parentId❌ Usually returns only the post's own reply count, not the reply content
Quote posts includedrowType: "quote", one search per post❌ Typically out of scope; needs a second tool
Reply/quote budgeted separately from posts✅ Raising maxRepliesPerTweet never costs post rows❌ Commonly a single shared item cap across everything
Honest partial-result reportingreplyRecoveryRatio, threadStatus, threadSkippedReason on every post❌ Usually silent — an empty thread looks identical to "no replies exist"
Works without login for post data✅ Profile timelines run on X's guest-token flowVaries by tool

If you're building an AI agent or RAG pipeline, the "replies as their own rows" row is the decision-maker — reconstructing a conversation tree from a bare reply count inside an agent loop is not something you can do at all, let alone reliably.


🔢 How many results can you scrape with this scraper?

There is no single result cap — the ceiling is per-post and per-target. maxTweets tops out at 100 posts per target (X's own limit on this surface, matched by the schema's maximum). Under each kept post, maxRepliesPerTweet caps out at 200 reply rows and maxQuoteTweetsPerTweet at 50 quote rows, so one target can yield up to 100 × (1 + 200 + 50) = 25,100 rows in the extreme case, before withReplies and minRepliesToFetch filtering.

Pagination runs as cursor walks under the hood: the profile timeline fetches up to 6 pages of 40 raw posts before applying your sort and cap; the conversation walk under each post fetches up to 12 pages of replies; the quote-post and keyword-search surfaces fetch up to 5 pages of 20. Reply depth 3 additionally re-queries up to the first 10 answered replies per post to pull their own children. startUrls accepts multiple targets in one run, and totals scale linearly with how many you provide. No benchmark timing is published — actual throughput depends on X's live rate-limit state at the moment you run.


🔌 Integrate this scraper and automate your workflow

This scraper works with any language or tool that can send an HTTP request.

REST API integration

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_API_TOKEN>")
run = client.actor("x-twitter-user-profile-and-tweets-scraper-and-reply-threads").call(
run_input={
"startUrls": ["https://x.com/NASA"],
"maxTweets": 10,
"scrapeReplyThreads": True,
}
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item["rowType"], item.get("username"), item.get("text"))

Works in Python, Node.js, Go, Ruby, cURL — any client that can call the Apify API with your token.

Automation platforms (n8n, Make)

Apify publishes official integrations for both Make and n8n (apify.com/integrations, checked 2026-08-04): add the Apify module in a Make scenario, or the Apify node in an n8n workflow, point it at this Actor, pass your input as JSON, and the resulting rows land directly in the next step of your automation — no custom code required.


Scraping publicly accessible data is generally lawful. This scraper returns only data X serves publicly — or to the session cookie you personally supply — including profile bios, post text, engagement counts, and the same for replies and quote posts. Because that includes personal data about identifiable people (usernames, display names, bios, locations, follower counts, join dates), collecting and storing it falls under data protection law such as the EU GDPR and the US CCPA/CPRA wherever those regimes apply to you or the people in your dataset. Scraping public data isn't itself prohibited by these laws, but you need a lawful basis for storing and using it, should honor data-subject rights (access, deletion, objection) on request, and shouldn't retain more than your purpose requires. X's own Terms of Service separately govern your use of its platform. Consult legal counsel for commercial use cases involving bulk personal data.


❓ Frequently asked questions

Does this scraper work without an X (Twitter) account?

Partially. Profile timelines and post rows run fully logged out over X's guest-token flow — no account needed. Replies, quote posts, and keyword search need authToken + ct0 cookies from a logged-in x.com session; X answers those three surfaces with HTTP 404 and an empty body to logged-out clients (verified live 2026-08-02).

How often is the scraped data updated?

Every run fetches live from X at request time. There's no cache — each run reflects whatever X's guest-token or authenticated GraphQL endpoints return at that moment.

What happens if a profile is suspended or a post is deleted?

If a profile can't be resolved (suspended, renamed, or non-existent), the run logs the failure for that target and continues with the rest of startUrls. If a post's conversation returns nothing, the post row still gets pushed, with threadStatus and threadSkippedReason explaining why (no_replies, rate_limited, fetch_failed, etc.) instead of the row silently looking like the post had no replies.

Can I scrape private or protected X accounts?

No. Only content the guest-token flow or your supplied session can see is returned — protected/locked accounts and content restricted to followers are not accessible.

What happens if my X session cookies expire or are invalid?

The reply, quote, and search surfaces raise an "unauthorised" error for that call and the affected post rows record it via threadStatus/threadSkippedReason rather than crashing the run; post rows keep flowing regardless, since they don't need the session at all.

Does this scraper work for AI agent workflows and LLM pipelines?

Yes. It's callable as an HTTP endpoint via the Apify API or apify_client from any agent framework. Every row is typed JSON with stable field names — no HTML, no parsing step before you pass it to an LLM.

How does this scraper handle X (Twitter)'s anti-bot system?

Requests run over curl_cffi with Chrome TLS impersonation (chrome131), because X answers plain-TLS clients differently than real browsers. Apify Residential proxy is wired in by default. The Actor reads X's own x-rate-limit-remaining / x-rate-limit-reset headers and backs off for up to 90 seconds with one retry on HTTP 429 instead of hammering the same window, and it re-discovers X's current GraphQL query IDs live from X's own JS bundle each run, falling back to pinned IDs only if live discovery fails.

How does this scraper compare to other X (Twitter) scrapers?

Most generic Twitter/X scrapers return only a profile's own posts. Turning each post into a reply tree with quote posts and honest recovery stats (repliesClaimed vs repliesCollected) typically means stitching together a second tool or hand-rolled pagination. This Actor keeps posts, replies, and quote posts budgeted separately in one run and one dataset.

Does this scraper return data in a format LLMs can use directly?

Yes — typed, normalized JSON with stable field names across all three row types. Pass it directly into an LLM context window, index it into a vector store, or route it through an agent tool without a parsing step.

Can I use this scraper without managing proxies?

Yes. Apify Residential proxy is configured by default via proxyConfiguration and rotated automatically per request; you can swap in your own proxy groups through the same field, but residential is the default because X answers datacenter IP ranges inconsistently.

What happens when X (Twitter) changes its structure or blocks the scraper?

The Actor re-discovers X's GraphQL query IDs and required feature flags live at the start of each run rather than hard-coding them, so it keeps working as X rotates them. Output field names and types stay stable on your end. No numeric turnaround time is promised for platform-side changes.


💬 Your feedback

Found a bug or missing a field? We want to know. Open an issue or a message through the Actor's page on the Apify Store, or use the Console's built-in support/issue link on the run page — reports get triaged against the live X payload, not against a stale schema.