Twitter / X Tweet Scraper API
Our Twitter tweet scraper turns any tweet URL or numeric status id into structured JSON: the full text, the author, favorite and reply counts, language, entities, and any attached media, all from one request with no login and no developer account.
Why Twitter / X Tweet data sits behind a login wall
X shut its free API tier in 2023 and now starts paid access around 100 dollars a month, while a logged-out visit to a tweet returns a JavaScript shell that hides the text behind a login wall. Reading one public tweet used to be a single GET; today it is an auth-gated, rate-limited endpoint or a brittle scrape.
One request to the Twitter / X Tweet Scraper API
curl "https://api.twitterscraperapi.com/api/v1/xtwitter/tweet?url=https://x.com/jack/status/20&api_key=$API_KEY" import requests, os
BASE = "https://api.twitterscraperapi.com"
API_KEY = os.environ["API_KEY"]
# Pass a full tweet URL or just the numeric status id.
resp = requests.get(
f"{BASE}/api/v1/xtwitter/tweet",
params={
"url": "https://x.com/jack/status/20", # or id="20"
"api_key": API_KEY,
},
timeout=30,
)
tweet = resp.json()
print(tweet["user"]["screen_name"], "-", tweet["text"])
print(tweet["favorite_count"], "favorites,", tweet["reply_count"], "replies")
print("posted", tweet["created_at"], "in", tweet["lang"]) Parameters
| Parameter | Required | Default | Notes |
|---|---|---|---|
url | optional | - | Any tweet URL, e.g. https://x.com/jack/status/20 or a twitter.com/.../status/ |
id | optional | - | The numeric tweet/status id on its own, e.g. 20. One of id or url is required. |
lang | optional | en | BCP-47 language hint for the tweet payload, e.g. en, es, ja. Defaults to en. |
api_key | required | - | Your API key, passed as a query parameter. Get one free at signup. |
The Twitter / X Tweet Scraper API response, field by field
{
"id": "20",
"id_str": "20",
"url": "https://x.com/jack/status/20",
"socialPlatform": "twitter",
"text": "just setting up my twttr",
"full_text": "just setting up my twttr",
"lang": "en",
"created_at": "2006-03-21T20:50:14.000Z",
"favorite_count": 308537,
"reply_count": 17947,
"conversation_count": 17947,
"retweet_count": null,
"quote_count": null,
"views": null,
"possibly_sensitive": null,
"is_edited": false,
"user": {
"screen_name": "jack",
"name": "jack",
"id_str": "12",
"is_blue_verified": true,
"verified": false,
"profile_image_url_https": "https://pbs.twimg.com/profile_images/1661201415899951105/azNjKOSH_normal.jpg",
"url": "https://x.com/jack"
},
"entities": {
"urls": [],
"user_mentions": [],
"hashtags": [],
"symbols": []
},
"media": [],
"thumbnail": null,
"price": null,
"currency": "USD",
"rating": null,
"reviews_count": null
} | Field | Type | Description |
|---|---|---|
id_str | string | The tweet's numeric status id as a string, the stable identifier for the post. |
url | string | Canonical tweet URL, https://x.com/ |
text | string | The tweet body. full_text carries the same value for consistency with X's own field name. |
lang | string | Detected language of the tweet as a BCP-47 code, e.g. en. |
created_at | string | ISO 8601 timestamp of when the tweet was posted. |
favorite_count | integer | Number of likes. Guaranteed on the response along with reply_count. |
reply_count | integer | Number of replies, taken from conversation_count. Guaranteed on the response. |
conversation_count | integer | Reply count for the conversation, equal to reply_count. |
retweet_count | integer or null | Retweets. Best-effort: X omits it on many tweets, in which case it returns null. |
quote_count | integer or null | Quote tweets. Best-effort: null when X does not include it. |
views | integer or null | View or impression count. Best-effort: present only for some tweets, otherwise null. |
is_edited | boolean or null | True when the tweet has been edited, false when not, null when X omits the flag. |
user | object | The author: screen_name, name, id_str, is_blue_verified, verified, profile_image_url_https, and url. |
entities | object | Parsed entities: urls, user_mentions, hashtags, and symbols. Any of them may be an empty array. |
media | array | URLs of any attached photos or video thumbnails. thumbnail holds the first one, or null when the tweet has no media. |
Where this Twitter / X Tweet data goes to work
Enrich saved tweet links
Track engagement over time
Social listening and mentions
Embed tweets in your app
Archive posts as clean JSON
Feed tweets to an LLM
What sets our Twitter / X Tweet Scraper API apart
Pass a tweet URL or a bare status id and we return validated JSON: text, author, favorites, replies, language, entities, and media, with no OAuth, no paid X developer plan, and no login cookie to source. Every request runs through rotating proxies and retries and comes back in about 2.6 seconds with a stable schema, so favorites and replies are always present and best-effort fields like views and retweets return null rather than breaking your parser.
URL or status id input
No login or paid X plan
Guaranteed engagement fields
Anti-bot and proxy rotation
Entities and media parsed out
Validated JSON schema
Twitter / X Tweet Scraper API or the official X API
| Our API | DIY (requests / headless) | Official X API v2 | |
|---|---|---|---|
| Input by URL or id | Yes, tweet URL or status id | Manual fetch and JSON dig | Tweet lookup by id, OAuth required |
| Setup | API key only | Proxies, headless browser, parser | Developer account plus paid tier |
| Cost to read one tweet | Free tier, then per successful request | Free code, but you run the proxies | Paid plans start around 100 dollars a month |
| Logged-out access | Handled for you | Login wall returns a JS shell | Auth token required on every call |
| Anti-bot and proxies | Built in | You build and maintain it | Not applicable |
| Output | Stable flat JSON | Whatever you parse from the shell | Nested JSON you map yourself |
Start free, pay as you grow
| Plan | Price | Best for |
|---|---|---|
| Free | 1,000 requests | Testing and small jobs |
| Pro | $0.60 / 1k | Production workloads |
| Pay-as-you-go | $0.90 / 1k | Spiky or one-off volume |
Median response 2.6s. You only pay for successful requests.
FAQ
A Twitter tweet scraper is a tool that reads a public tweet and returns its data in a structured format. Our tweet scraper API takes a tweet URL or a numeric status id and returns the full text, author, created_at timestamp, language, favorite and reply counts, entities, and any media as JSON from a single request, with no login required.
No. You authenticate with a single twitterscraperapi key passed as the api_key query parameter. There is no X developer account to apply for, no OAuth flow, and no paid X API tier, which as of 2023 starts at around 100 dollars a month. The free tier includes 1,000 requests so you can test first.
Either works. Pass the full tweet URL, for example https://x.com/jack/status/20 or a twitter.com/.../status/
Favorite count (likes) and reply count are guaranteed on every response. Retweet count, quote count, and view count are best-effort: X includes them on some tweets but not all, so when they are absent our API returns null for that field rather than omitting it, which keeps the JSON shape stable for your parser.
Yes. The entities object breaks out urls, user_mentions, hashtags, and symbols as arrays, any of which can be empty. Attached photos and video thumbnails come back as URLs in the media array, and the first one is also set as thumbnail, or null when the tweet has no media.
Median end-to-end response is about 2.6 seconds, which includes proxy routing, anti-bot handling, retries, and parsing. One call returns the whole tweet, author, and engagement together, so you do not chain extra requests to assemble a single post.
No. The API reads what is publicly visible, so a deleted, protected, or age-gated tweet has no public payload to return, and the request reports a clear not-found style error instead of guessing. Public tweets from public accounts are what it is built to read.