Twitter (X) List Scraper - Full Tweets, Views & Authors avatar

Twitter (X) List Scraper - Full Tweets, Views & Authors

Pricing

Pay per event

Go to Apify Store
Twitter (X) List Scraper - Full Tweets, Views & Authors

Twitter (X) List Scraper - Full Tweets, Views & Authors

X's list timelines are served only to a signed-in session, and this Actor brings its own. One row per tweet: full text, likes, retweets, replies, quotes, bookmarks, views, hashtags, media and the author. No login needed from you. $0.40 per 1,000 tweets.

Pricing

Pay per event

Rating

0.0

(0)

Developer

Dami's Studio

Dami's Studio

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

Twitter (X) List Scraper

Give it an X list id and it walks that list's timeline and writes one row per tweet: the full untruncated text, likeCount, retweetCount, replyCount, quoteCount, bookmarkCount, viewCount, createdAt, lang, hashtags, mentions, urls, media, and an author object with the handle, display name, follower count and verification flags.

Lists are the timeline worth scraping because somebody already did the filtering. A well-kept list is a hand-picked set of accounts on one subject, which beats a keyword search that drags in every spam reply using the word.

About the login, up front

X only serves list timelines to a signed-in session. There is no guest route to them. The ListLatestTweetsTimeline operation isn't registered on X's guest host at all, and no proxy changes that.

So the Actor carries an account session of its own. You don't need to log in or find a cookie. But be clear about what that means: something is logged in, it's shared across everyone running the Actor, and X counts rate limits per account rather than per caller. Under heavy concurrent use it throttles, and your run can come back short with a BLOCKED row explaining why.

If your throughput shouldn't depend on how busy the Actor is, put your own cookie in sessionCookies and the run uses only yours. Log in to x.com (a throwaway account is fine), press F12, open Application → Cookies → https://x.com, copy auth_token and ct0, and paste them as auth_token=XXXX; ct0=YYYY. One line per account. Several lines get rotated, and one going quiet doesn't stop the run. Nothing you paste there is ever printed to the run log. It does sit in the run's saved input like every other field, which is the reason to use a throwaway account and not your real one.

Input

{
"startUrls": ["https://x.com/i/lists/34179516"],
"maxItems": 250
}
FieldWhat it does
listIdsThe number in x.com/i/lists/<id>. One or many.
startUrlsOr paste the full list URLs; the id is read out of them.
maxItemsTweets per run. Default 100, ceiling 5,000. You pay per tweet.
sessionCookiesOptional. Your own auth_token=...; ct0=... lines, for a rate limit nobody else draws on.
proxyConfigurationRotating Apify datacenter addresses by default.
notionConnector / notionParentIdOptional. Push the rows into a Notion data source.

Run it with no list at all and you get one labelled _sample tweet, uncharged, so you can see the shape before you spend anything.

Metered Apify proxy groups (Residential, Google SERP) are not selectable here. If you pick one it is swapped for datacenter addresses and the log says so, so a run can't quietly run up a per-gigabyte bandwidth bill. Your own proxy servers, pasted under Custom proxies, are used exactly as given.

A row

{
"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",
"followersCount": 96000000,
"verified": true
}
}

Billing

$0.40 per 1,000 tweets ($0.0004 each), plus $0.001 each time a run starts. Same rate on the free plan as on any paid one. No volume tiers, no per-list fee.

EventPriceFires
Actor start$0.001Once per run, whatever happens
Tweet scraped$0.0004Once per real tweet written to the dataset

The _sample row isn't charged. Diagnostic rows aren't charged. Tweets are deduplicated by id within a run, including across several lists, so you never pay twice for the same one. A run that comes back empty costs the $0.001 start fee and nothing else.

Limits

The built-in session is shared. X limits per account, so at busy moments runs throttle and can return fewer tweets than you asked for. Your own cookie in sessionCookies fixes that.

Sessions wear out. A 429 is treated as a healthy account going too fast: the run backs off and rotates to another session rather than retiring that one. A real 401, or a body that says logged out, evicts the session. When nothing usable is left the run returns the labelled sample row instead of failing, and charges nothing for it.

Private and deleted lists aren't readable. If the session can't see the list, you get a diagnostic row that says so.

maxItems caps at 5,000 per run. For a full sweep of a very long timeline, split it across runs.

Some fields come back null. viewCount is missing on older tweets and bookmarkCount isn't always exposed. Media URLs expire, so download anything you want to keep.

Text is returned as X published it, in the original language. Nothing is translated or scored.

FAQ

Do I need cookies? No. Runs work as-is.

Then why is sessionCookies there? Because the built-in session is shared and X limits per account. Your own cookie gives you a limit no other run touches.

Where's the list id? The number in the URL: x.com/i/lists/3417951634179516. Or paste the whole URL into startUrls.

Will a different proxy raise the rate limit? No. The limit that bites on a list timeline is per account, not per address.

Why did I get a diagnostic row? So you know what happened instead of getting silence. Check sessionState: ok means the session was fine and the list was the problem, exhausted means nothing was left to read it with. A re-run, or your own cookie, clears the second one.