X (Twitter) Post Detail Scraper
Pricing
from $0.15 / 1,000 results
X (Twitter) Post Detail Scraper
Get full detail for any public X (Twitter) tweet by ID or URL. Returns text, media (photos/videos), engagement counts (likes/retweets/replies/views), entities (hashtags/URLs/mentions), and author info. HTTP-only, no login.
Pricing
from $0.15 / 1,000 results
Rating
0.0
(0)
Developer
Farhan Febrian Nauval
Maintained by CommunityActor stats
0
Bookmarked
42
Total users
15
Monthly active users
12 hours
Issues response
11 days ago
Last modified
Categories
Share
Fetch the full detail of any public X (Twitter) tweet by URL or status ID — text, media, engagement counters, author, timestamp, mentions, and hashtags — in clean structured JSON.
Why use this actor
- No account / no login required — paste a tweet URL or status ID and get the data back.
- No API key needed — X's official API is paid and rate-limited; this actor returns the same data the public web app shows.
- Full tweet text — including long-form (premium) tweets over 280 characters, returned in
full_text(isNoteTweet: true). - X Articles — detected with
isArticle: true; title, plain-text body and cover image come back underarticle. - Media URLs — every photo size and video bitrate variant is included in
extended_entities.media. - Engagement counters — like, retweet, reply, quote, bookmark, and view counts in one shot.
- Author snapshot — handle, display name, followers, profile image, verified status captured at scrape time.
- Bulk input — pass a mix of URLs and status IDs in one run; one clean dataset row per tweet.
- Stable JSON output suitable for pipelines, spreadsheets, and databases — every row carries
_input,_source,_scrapedAtenvelope fields so you can join results back to your input list.
How it works
- You provide a list of tweet URLs (
https://twitter.com/jack/status/20,https://x.com/jack/status/20) or bare status IDs (20). - The actor fetches each tweet the same way X's web app does, then assembles a flat JSON record with full text, media, counters, and author.
- Results stream into your dataset, ready to download as JSON, CSV, or Excel.
You do not need to manage scrapers, browsers, or rotating IPs — all handled internally. If the primary path is unavailable, the actor by default falls back to a secondary source so you still get a result. Set fallback: false to get primary-source rows only, and maxRetries: 0 to send each request exactly once.
Input
{"tweets": ["https://twitter.com/jack/status/20","1445078208190291973"],"fallback": true,"maxRetries": 4,"proxyConfiguration": {"useApifyProxy": true,"apifyProxyGroups": ["DATACENTER"]}}
| Field | Type | Description |
|---|---|---|
tweets | array | List of tweet URLs or status IDs. Accepts twitter.com/<user>/status/<id>, x.com/<user>/status/<id>, mobile URLs, and bare numeric IDs. Mix freely. |
fallback | boolean | Default true. When the primary source cannot return a tweet, try the secondary source (rows tagged _source: "S2-fallback", simpler shape). false = primary only; a primary failure becomes an error row tagged _source: "S1-primary". |
maxRetries | integer | Default 4 (5 attempts). How many times a failed primary request is re-sent on rate limit, server error, network error, or one guest-token refresh. 0 = one attempt per tweet, no retries. |
proxyConfiguration | object | Apify Proxy settings. Datacenter proxy works for most cases; switch to residential for very large jobs. |
Output
Input: https://twitter.com/jack/status/20
{"_input": "https://twitter.com/jack/status/20","_source": "S1-primary","_scrapedAt": "2026-05-18T11:04:30.976327+00:00","rest_id": "20","id_str": "20","conversation_id_str": "20","user_id_str": "12","created_at": "Tue Mar 21 20:50:14 +0000 2006","lang": "en","full_text": "just setting up my twttr","display_text_range": [0, 24],"favorite_count": 311853,"retweet_count": 126211,"reply_count": 17883,"quote_count": 6481,"bookmark_count": 21449,"views": { "state": "Enabled" },"is_quote_status": false,"source": "<a href=\"http://twitter.com\" rel=\"nofollow\">Twitter Web Client</a>","entities": {"hashtags": [],"symbols": [],"urls": [],"user_mentions": []},"author": {"rest_id": "12","screen_name": "jack","name": "jack","description": "no state is the best state","created_at": "Tue Mar 21 20:50:14 +0000 2006","followers_count": 7537422,"friends_count": 3,"statuses_count": 30509,"media_count": 2963,"listed_count": 33146,"favourites_count": 38827,"is_blue_verified": true,"profile_banner_url": "https://pbs.twimg.com/profile_banners/12/1742427520","url": "https://t.co/ZEpOg6rn5L"}}
| Field | Type | Description |
|---|---|---|
_input | string | The URL or ID exactly as you supplied it. Use this to join results back to your input list. |
_source | string | Internal tag for the path used to fetch the record. S1-primary is the fastest, richest path; S2-fallback is a simpler shape used when the primary path is unavailable. |
_scrapedAt | string | ISO-8601 UTC timestamp when the record was scraped. |
rest_id | string | Numeric tweet ID as a string. Stable identifier. |
id_str | string | Same as rest_id; kept for compatibility with older tooling. |
conversation_id_str | string | ID of the root tweet in the conversation thread. Equals rest_id for top-level tweets. |
user_id_str | string | Numeric ID of the author. |
created_at | string | Tweet publication time in X's native format. |
lang | string | Auto-detected language code (e.g. en, id, ja). |
full_text | string | Complete tweet text. For long-form (premium) posts this is the full note body, not the ~280-character preview. For an Article it is only the t.co link — read article instead. |
isNoteTweet | boolean | true when the post is a long-form note; full_text then holds the full body and note_tweet the raw note object. |
fullTextSource | string | note_tweet or legacy — which object full_text was taken from. |
isArticle | boolean | true when the post is an X Article. |
article | object | Present only when isArticle is true: rest_id, url, title, preview_text, plain_text (full body as plain text), cover_image_url, first_published_at_secs, modified_at_secs. |
display_text_range | array | [start, end] character offsets of the visible portion (excludes trailing media URLs). |
favorite_count | integer | Like count at scrape time. |
retweet_count | integer | Retweet count. |
reply_count | integer | Reply count. |
quote_count | integer | Quote tweet count. |
bookmark_count | integer | Bookmark count. |
views | object | View counter. count (string) is present when public; state indicates whether counts are exposed. |
is_quote_status | boolean | true if this tweet quotes another tweet. |
source | string | Client used to post the tweet (HTML snippet — typically "Twitter for iPhone", "Twitter Web Client", etc.). |
entities | object | Parsed entities: hashtags, user_mentions, urls, symbols. |
extended_entities.media | array | Every photo, video, and animated-GIF attachment, one entry per item with its own id_str/media_key and type (photo, video, animated_gif), in post order — including posts that mix photos and videos. Videos and GIFs carry video_info.variants. Present only when the tweet has media. |
author | object | Snapshot of the tweet's author (handle, display name, followers, profile image, verified status, etc.). |
Error envelope
Tweets that are deleted, protected, or otherwise unreachable return a structured error instead of crashing the run:
{"_input": "https://twitter.com/jack/status/999999999999999999","_error": "not_found","_errorDetail": "S1: TweetUnavailable: NotFound; S2: 404","_source": "S2-fallback","_scrapedAt": "2026-05-18T11:05:14.012345+00:00"}
_error values:
| Value | Meaning |
|---|---|
not_found | Tweet was deleted, never existed, or the ID is invalid. |
private | Author's account is protected — only their approved followers can see this tweet. |
blocked | Tweet exists but X declined to serve it (age-restricted, region-blocked, or temporarily unavailable). |
invalid_request | Input could not be parsed as a tweet URL or numeric ID. |
Filter on _error to triage failed rows.
Pricing
Pay per event:
- Actor start — $0.005 per GB of run memory (minimum one). This actor is HTTP-only, so 256–512 MB is plenty; the default 4 GB means 4 start events.
- Result — $0.00075 per dataset row on the Free plan (down to $0.00015 on higher plans). Every row counts, including error rows.
- Platform usage (compute, proxy) is billed separately at Apify's standard rates.
A run's maximum-cost limit (maxTotalChargeUsd) caps the event charges above: once it is reached, no further rows are pushed and the run is aborted.
Other Sosmed Actors
| Platform | Actor | Best for |
|---|---|---|
| Twitter / X | X Account Scraper | Profile + follower counts for any handle |
| Twitter / X | X Account Tweets Scraper | All tweets from a user's timeline |
| Twitter / X | X Search Scraper | Keyword and hashtag search across tweets |
| Bluesky | Bluesky Post Detail Scraper | Single post detail on Bluesky |
| Threads | Threads Post Detail Scraper | Single post detail on Threads |
| Instagram Post Detail Scraper | Single post detail on Instagram | |
| Reddit Post Detail Scraper | Single post + comments thread on Reddit |
Browse the full catalog at apify.com/xtracto.
Notes
- Deleted tweets return
{"_error": "not_found", "_input": "..."}— they cannot be recovered after the author or X removes them. - Protected accounts cannot be fetched. If the author has set their tweets to "Protected" (followers-only), the tweet returns
{"_error": "private", ...}. - View counts may be missing (
views.countabsent) for very new tweets or accounts that opted out of public view-count display. - Long-form tweets (premium tweets over 280 characters) return the full body in
full_text— no truncation. - Media variants: when present,
extended_entities.mediacarries every photo size and the full mp4 bitrate ladder for videos, verbatim from X's response — ready for direct download. - Counters are eventually-consistent and may lag the live network by a few minutes.
- Fallback path: rows from the secondary source (
_source: "S2-fallback") have a different, simpler shape —textinstead offull_text,mediaDetailsinstead ofextended_entities,userinstead ofauthor,id_strbut norest_id, long-form notes truncated, noretweet_count/reply_count/quote_count. Setfallback: falseif your pipeline maps only the primary shape. - Articles:
full_textof an Article post is just a link. The body is inarticle.plain_text; rich formatting and inline article media are not included.