Twitter (X) List Scraper
Scrape every tweet from any X (Twitter) list: full text, likes, retweets, views, media, hashtags and author profile.
How it works
- 1Open it on Apify
Hit Run on Apify — it opens the tool in the cloud, no install.
- 2Set the inputs
Adjust
listIds,startUrls,maxItems(sensible defaults are pre-filled). - 3Click Run
The tool runs on Apify’s cloud and collects the data for you.
- 4Export the results
Download as JSON, CSV or Excel, or pipe straight into your app, Google Sheets, or an AI agent.
Pricing
$0.0004 per tweet = $0.4 per 1,000
| You are charged for | When | Price |
|---|---|---|
| Tweet scraped | Charged per tweet returned from the X list timeline. | $0.0004 |
| Actor start | Charged once when a run starts. Covers the fixed cost of spinning up the run so that small runs remain viable. | $0.001 |
Pay-per-event pricing: you are billed per result, not per subscription — a run that returns nothing costs nothing beyond the start fee. Billing is handled by Apify on your own account. These are the live Apify store prices, in effect since 2026-08-04, and they are what you are actually charged.
Inputs
| Field | What it does | Type |
|---|---|---|
listIds | X list ids (the number in x.com/i/lists/<id>). | array |
startUrls | Or paste list URLs (https://x.com/i/lists/34179516). | array |
maxItems | Charged per tweet. | integer |
sessionCookies | Optional. Runs use a built-in session by default, and that session is shared, so under heavy concurrent load it is rate-limited across everyone using it. Supply your own account cookie here and the run uses only yours, giving you a rate limit nobody else draws on. In Chrome, logged in to x.com: F12 -> Application -> Cookies -> https://x.com, and copy auth_token and ct0. Paste one account per line as 'auth_token=XXXX; ct0=YYYY'. Several lines means several accounts, rotated. Stored as a secret and never logged. | array |
notionConnector | Optional Notion delivery. | string |
notionParentId | Optional Notion data-source id. | string |
What you get
A structured dataset — each result includes fields like:
textlikeCountretweetCountcreatedAturlExport every run as JSON, CSV or Excel, or send it to your app, a database, Google Sheets, or an AI agent.
Related tools in Social Media Scrapers
Other ready-to-run tools in the same category — all pay-per-use on the Apify cloud.
Threads Scraper
Scrape public Threads profiles and recent posts without login: bios, followers, post text, likes, timestamps and media URLs. From $0.40 per 1,000 results.
Facebook Pages Scraper
Scrape public Facebook Page names, categories, likes, talking-about counts, verified badges and images without login.
LinkedIn Profile Posts Scraper
LinkedIn profile posts scraper at $0.90 per 1,000 posts, flat on every plan. Post text, author, image, publish time and URL.
LinkedIn Company Posts Scraper
LinkedIn company posts scraper at $0.90 per 1,000 posts plus a $0.001 run start. Public post text, reactions, comments and URLs. No login or cookies needed.
LinkedIn Post Comments Scraper
Scrape public LinkedIn post comments: author name, profile URL, reaction count. No login or cookie. Up to 10 per post.
RedNote Scraper
Scrape public RedNote (Xiaohongshu) notes: description, author, likes, collects, comments, shares and images.
Where this tool sits
- Categories
- Social Media Scrapers
- Platforms
- X (Twitter)
⚡ Twitter (X) List Scraper — Tweets from Any X List
Pull every tweet from any X (Twitter) List timeline. Point it at a list id or URL and get back the full tweet text plus every engagement metric — likes, retweets, replies, quotes, bookmarks and views — with author, media, hashtags and mentions. Export to JSON, CSV or Excel, call it from the API, or have results delivered straight to Notion. $0.40 per 1,000 tweets plus a $0.001 run-start fee — pay only for tweets actually returned.
> X gates List timelines behind a login — there is no keyless path to them. The Actor carries a built-in session, so a run needs nothing from you but a list id. That session is shared, so at heavy concurrent load you can add your own cookie in sessionCookies for a rate limit nobody else draws on.
Why this scraper wins
- 💸 Cheapest on the market, with no per-query surcharge — $0.40 / 1,000 tweets plus $0.001 per run start, billed per tweet actually returned. Nothing extra per list queried, no monthly plan, no volume tier. Empty or failed runs cost only the $0.001 start fee.
- 🔁 Runs out of the box — no cookie to go and find, no API key to register. Add your own cookies if you want to and the run rotates them, backs off on a
429, and drops a session that has stopped working instead of failing the run. - 🧹 Clean, flat output — one tidy record per tweet, ready for spreadsheets, dashboards or LLM pipelines. No raw nested GraphQL soup.
- 🔂 Auto-dedupe — the same tweet is never returned (or charged) twice in a run, even across multiple lists.
- 🛡️ Rotating datacenter proxy by default — large IP pool, nothing billed per gigabyte. Bring your own residential/ISP proxy servers in the Proxy field (Custom proxies) if you want them; they are used exactly as given.
- 📬 Built-in delivery — optionally push every run straight into Notion via Apify connectors, with zero extra code.
- 🚦 Honest errors — if X blocks, rate-limits or a list is inaccessible, you get a clear diagnostic row (
BLOCKED,NO_RESULTS, …) instead of silent emptiness.
What you can scrape
| Mode | Input | Notes |
|---|---|---|
| List by id | listIds (the number in x.com/i/lists/<id>) | Scrape one or many lists in a single run |
| List by URL | startUrls (https://x.com/i/lists/<id>) | List id is parsed out of the URL automatically |
The login is handled for you
A List timeline is only served to a signed-in session. That is an allow-list on X's side, not a fingerprint or an address problem, and no proxy changes it. The Actor therefore carries a built-in session and you do not have to set anything up.
The built-in session is shared, and X counts its limits per account rather than per caller. At heavy concurrent load it will throttle, and a run can then come back short or with a BLOCKED diagnostic row saying so. That is the honest trade for zero setup. If you are pulling at volume, or you would rather your throughput did not depend on how busy the Actor is, put your own cookie in sessionCookies and the run uses only yours.
How to get your own cookie (1 minute): 1. Log in to x.com in your browser (a throwaway account is fine, and a sensible choice). 2. Press F12 → Application tab → Cookies → https://x.com. 3. Copy the values of auth_token and ct0. 4. Paste into sessionCookies as auth_token=XXXX; ct0=YYYY — one account per line; several lines are rotated, and one going quiet does not stop the run.
> If no session is usable at all, the run still succeeds: it returns one clearly labelled _sample tweet so you can see the exact output shape, and no per-tweet fee is charged for it — that run costs the $0.001 start fee and nothing else.
Input
listIds— X list ids (e.g.34179516). One or many.startUrls— or paste full list URLs (https://x.com/i/lists/34179516); the id is extracted for you.sessionCookies*(optional)* — runs work without it. Supply one or more of your own account cookies, formatauth_token=XXXX; ct0=YYYY, one per line, for a rate limit no other run shares; the Actor rotates across them on a rate-limit. Stored as a secret.maxItems— cap the number of tweets (default100, max5000). You pay per tweet.proxyConfiguration— Rotating datacenter addresses by default. Per-gigabyte metered proxy tiers are not offered and are swapped for rotating datacenter addresses automatically, so a run can never quietly run up a bandwidth bill; to use residential addresses, paste your own proxy servers under Custom proxies and they are used verbatim.notionConnector/notionParentId— optional, deliver results to a Notion data source.
Input field names follow the conventions used across similar Actors, so pointing an existing workflow at this one is usually a drop-in change.
Example input
{
"startUrls": ["https://x.com/i/lists/34179516"],
"listIds": ["1234567890123456789"],
"maxItems": 250,
"proxyConfiguration": { "useApifyProxy": true }
}
Output (one record per tweet)
{
"id": "1789000000000000000",
"url": "https://x.com/nasa/status/1789000000000000000",
"text": "We're going back to the Moon. 🌙",
"createdAt": "Mon May 13 14:02:11 +0000 2024",
"lang": "en",
"replyCount": 312,
"retweetCount": 1840,
"likeCount": 21500,
"quoteCount": 96,
"bookmarkCount": 410,
"viewCount": 1230000,
"isReply": false,
"isRetweet": false,
"isQuote": false,
"conversationId": "1789000000000000000",
"hashtags": ["Artemis"],
"mentions": [],
"urls": [],
"media": [{ "type": "photo", "url": "https://pbs.twimg.com/media/xxx.jpg" }],
"author": {
"id": "11348282",
"userName": "NASA",
"name": "NASA",
"verified": true
}
}
Pricing
$0.40 per 1,000 tweets ($0.0004 each), plus $0.001 each time a run starts — the cheapest way to scrape X list timelines on the market, with no extra fee per list queried.
What bills and what does not:
| Event | Price | When it fires |
|---|---|---|
| Run start | $0.001 | Once per run, whatever the outcome |
| Tweet scraped | $0.0004 | Once per real tweet pushed to the dataset |
- Sample rows are free. The labelled
_sampletweet is never charged. - Diagnostics are free.
BLOCKED,NO_RESULTSand similar rows are not billed. - Duplicates are free. Auto-dedupe means the same tweet is never returned — or charged — twice in a run, even across several lists.
- Failed and empty runs cost the $0.001 start fee and nothing else.
Flat rate throughout: no volume tiers, no plan gates, and you are only charged for tweets actually returned.
Limitations — read before you buy
- List timelines require a logged-in session, and the built-in one is shared. X limits per account, not per caller, so at heavy concurrent load runs throttle and can come back short. Supply your own cookie in
sessionCookiesfor a limit nobody else draws on. - Sessions wear out. A session that is rate-limited or challenged is dropped for the rest of the run and the next one is used. When nothing usable is left, the run returns the labelled sample row instead of real tweets, uncharged, rather than failing.
- Private and deleted lists are not accessible. If the session reading the list cannot see it, you get a diagnostic row explaining that, not data.
maxItemscaps at 5,000 tweets per run. Very long list timelines are paginated; for a full historical sweep, split the work across runs.- Some fields can be null.
viewCountis absent on older tweets,bookmarkCountis not always exposed, and media URLs expire after a while — download anything you need to keep. - Rate limits are X's, not ours. On a
429the Actor paces itself and rotates to the next session rather than hammering the endpoint; a429never retires a session, because a throttled account is a healthy one going too fast. If everything is throttled at once, the run ends with aBLOCKEDdiagnostic row rather than silently returning a partial list. - Tweet text is returned as-is, including the original language; no translation or sentiment scoring is performed.
FAQ
Do I need account cookies? No. Runs work as they are. X does require a logged-in session to view a List timeline — there is no keyless route — but the Actor brings one.
Then why is sessionCookies there? Because the built-in session is shared and X limits per account. Supplying your own gives you a rate limit no other run touches, which is what you want for sustained volume. Add several of your own and the Actor rotates between them.
Where do I find the list id? It's the number in the list URL: x.com/i/lists/34179516 → 34179516. You can also just paste the full URL in startUrls.
Which proxy? The Actor rotates through Apify's datacenter pool by default (large pool, no per-gigabyte charge). If you already own residential or static-ISP proxy servers, paste them under Custom proxies and they are used verbatim. Note that the limit which actually bites on a List timeline is per ACCOUNT, not per address, so rotating addresses alone does not raise it.
It returned a diagnostic row — why? That's the Actor telling you exactly what happened (e.g. BLOCKED, NO_RESULTS) instead of failing silently. Each one carries a sessionState field: ok means the session was fine and the list itself was the problem, exhausted means nothing was left to read the list with, and a re-run — or your own cookie — clears it.