Tweet Scraper | X Scraper | $0.012/1K | 10x lower avatar

Tweet Scraper | X Scraper | $0.012/1K | 10x lower

Pricing

from $0.01 / 1,000 results

Go to Apify Store
Tweet Scraper | X Scraper | $0.012/1K | 10x lower

Tweet Scraper | X Scraper | $0.012/1K | 10x lower

Now $0.012 per 1,000 results, one tenth of the previous $0.12. Profiles, home tweets, one tweet with replies, following, and followers. Each profile, tweet, reply, or account is one result. Docs: https://www.opentwitter.com/docs

Pricing

from $0.01 / 1,000 results

Rating

0.0

(0)

Developer

Handian Geinais

Handian Geinais

Maintained by Community

Actor stats

2

Bookmarked

2

Total users

2

Monthly active users

14 days ago

Last modified

Share

Tweet Scraper | X Scraper

Look up public X (Twitter) data: a profile, home tweets, one tweet and the replies on that page, following, and followers.

Full field reference, including HTTP examples: https://www.opentwitter.com/docs

$0.012 per 1,000 results. That is one tenth of the previous $0.12 per 1,000. Apify charges one result for each row. Leave OpenTwitter API key blank. This Actor uses the key stored on it.

A name, @name, or an x.com profile link all work in Handles. Tweet ids and user ids are strings. A short number such as 1234567890 is rejected.

What each run accepts

FieldRequiredValues
What to fetchyestweets, profile, both, tweet, following, followers
Handlesyes, except One tweetOne account per line
Tweet id or status URLOne tweet only15–20 digits, or a status URL
User idnoNumeric id you already know. Skips one profile lookup
Countsee each sectionHome tweets: 20–40, default 20. Following and followers: 1–200, default 200
ConcurrencynoHow many accounts at once. Default 3, maximum 8
API base URLnoLeave https://api.opentwitter.com

Each successful item is one dataset row. Open Storage to see profile, tweet, or user. The table shows handle, endpoint, status, and ok.

A missing or suspended account is HTTP 404 and still one row:

{
"handle": "elonmusk",
"endpoint": "profile",
"status": 404,
"ok": false,
"error": "This account was not found"
}

A bad key, a bad parameter, no balance, or a server error is not written to the dataset and is not charged.

Profile

One public profile. Count is ignored. One profile is 1 result. A 404 is also 1 result.

Request:

{ "endpoint": "profile", "handles": ["elonmusk"] }

Calls POST https://api.opentwitter.com/v1/lookup/profile with { "handle": "elonmusk" }.

Response, one row:

{
"handle": "elonmusk",
"endpoint": "profile",
"status": 200,
"ok": true,
"profile": {
"user_id": "44196397",
"screen_name": "elonmusk",
"display_name": "Elon Musk",
"bio": "",
"location": "",
"website": "",
"followers_count": 0,
"following_count": 0,
"tweets_count": 0,
"likes_count": 0,
"verified": false,
"protected": false,
"avatar_url": "https://pbs.twimg.com/profile_images/1.jpg",
"banner_url": "https://pbs.twimg.com/profile_banners/1.jpg",
"created_at": "Tue Jun 02 00:00:00 +0000 2009"
}
}

Home tweets

Latest posts on the profile timeline, plus the pinned post on the first page. count must be 20–40. Default 20. One request to X returns at least 20 posts, so a smaller count is rejected. Leave cursor empty for the first page. next_cursor in the API response is the next page; pass it back as cursor to load that page only. The pinned post is first and has is_pinned: true. If it is already on the page, it is kept once and marked pinned. Each returned tweet is 1 result, including an extra pinned post. Duplicate tweet ids are removed. Zero tweets, or a 404, is still 1 result.

Request:

{ "endpoint": "tweets", "handles": ["elonmusk"], "count": 20 }

Calls POST https://api.opentwitter.com/v1/lookup/tweets with { "handle": "elonmusk", "count": 20 }. Add "user_id": "44196397" when you already know it.

Response, one row per tweet:

{
"handle": "elonmusk",
"endpoint": "tweets",
"status": 200,
"ok": true,
"tweet": {
"tweet_id": "1840000000000000002",
"text": "tweet text",
"created_at": "2026-09-17T10:00:00.000Z",
"url": "https://x.com/elonmusk/status/1840000000000000002",
"likes": 0,
"retweets": 0,
"replies": 0,
"views": 0,
"is_retweet": false,
"is_reply": false,
"is_quoted": false,
"is_pinned": true,
"urls": []
}
}

Several accounts. Default concurrency is 3, maximum 8.

{ "endpoint": "tweets", "handles": ["elonmusk", "nasa"], "count": 20, "concurrency": 3 }

Profile and tweets

Both in one run. Tweet count is 20–40, same floor as home tweets. cursor applies only to the tweets side. The dataset is split: one profile row, then one row per tweet. Each side is billed on its own. One side can fail while the other succeeds. A protected account can still return the profile, with tweets as a 404 row.

Request:

{ "endpoint": "both", "handles": ["elonmusk"], "count": 20 }

Calls POST https://api.opentwitter.com/v1/lookup with { "handle": "elonmusk", "count": 20 }.

Response rows use the same profile object as Profile and the same tweet object as Home tweets. endpoint on those rows is profile or tweets.

One tweet

That tweet, plus the replies on the same page. Handles and count are ignored. The main tweet and each reply are each 1 result. Duplicate ids are removed. Zero items, or a 404, is still 1 result.

Request. Keep the id a string. A status URL is accepted.

{ "endpoint": "tweet", "tweetId": "1840000000000000002" }
{ "endpoint": "tweet", "tweetId": "https://x.com/elonmusk/status/1840000000000000002" }

Calls POST https://api.opentwitter.com/v1/lookup/tweet with { "tweet_id": "1840000000000000002" }.

Response, one row for the tweet and one row for each reply. The shape is the same tweet object as Home tweets. A reply has "is_reply": true.

Following

Accounts this user follows, most recent first. count is 1–200, default 200. The lookup stops at that count, so the bill matches the accounts returned. Each account is 1 result. Duplicate user ids are removed. Zero accounts, or a 404, is still 1 result. X does not return the time they were followed. account_created_at is when that account was created.

Request:

{ "endpoint": "following", "handles": ["elonmusk"], "count": 50 }

Calls POST https://api.opentwitter.com/v1/lookup/following with { "handle": "elonmusk", "count": 50 }.

Response, one row per account:

{
"handle": "elonmusk",
"endpoint": "following",
"status": 200,
"ok": true,
"user": {
"user_id": "12",
"handle": "jack",
"name": "jack",
"bio": "",
"followers_count": 0,
"following_count": 0,
"tweets_count": 0,
"verified": false,
"protected": false,
"avatar_url": null,
"location": "",
"account_created_at": "Tue Mar 21 00:00:00 +0000 2006"
}
}

This run does not walk pages by itself. For the next page of home tweets, pass cursor from the previous API next_cursor. The dataset row is one tweet, so next_cursor is not its own column.

Followers

Accounts that follow this user. Same count rule and same user object as Following.

Request:

{ "endpoint": "followers", "handles": ["elonmusk"], "count": 50 }

Calls POST https://api.opentwitter.com/v1/lookup/followers with { "handle": "elonmusk", "count": 50 }.

Response rows use "endpoint": "followers" and the same user object as Following.

Not included

No keyword search, no lists, no date range, and no batch endpoint. More than 40 home tweets needs another run with cursor set to the previous next_cursor. More than 200 follow-list accounts needs another run the same way. This Actor does not monitor an account over time.