Twitter X Tweets Scraper Scraper - Repost and Quote avatar

Twitter X Tweets Scraper Scraper - Repost and Quote

Pricing

from $4.99 / 1,000 results

Go to Apify Store
Twitter X Tweets Scraper Scraper - Repost and Quote

Twitter X Tweets Scraper Scraper - Repost and Quote

Scrape tweets from X (Twitter) by keyword, hashtag, username, or URL. Collect tweet text, author details, timestamps, metrics, media, and replies. Ideal for sentiment analysis, trend tracking, research, monitoring, and building datasets at scale.

Pricing

from $4.99 / 1,000 results

Rating

0.0

(0)

Developer

API Empire

API Empire

Maintained by Community

Actor stats

0

Bookmarked

4

Total users

0

Monthly active users

2 days ago

Last modified

Share

X (Twitter) Scraper β€” Extract Posts, Original Posts and Reposters

Scrape X (Twitter) profiles and single posts, and this X (Twitter) scraper opens every repost and quote into the post that was actually shared β€” its own likes, replies, reposts, quotes, bookmarks and views, plus the original author's handle, follower count, bio and verified badge. Every response is typed, normalized JSON: no HTML, no selectors, no RT @somebody: string to parse yourself. Filter to amplification only, screen by the original author's audience size, or pull the roster of accounts that reposted a post. After reading this, you'll be able to turn a raw X timeline into a structured map of whose material an account amplifies, and how large those accounts are.


🐦 What is Twitter X Tweets Scraper Scraper - Repost and Quote?

It's an Apify Actor that scrapes X (Twitter) profile timelines and single post URLs, labels every row original, repost or quote, and β€” for the shared rows β€” resolves the source post into a full original_post object rather than leaving it as a truncated reference. No X account or login is required for that core path; a session (two cookie values) is needed only for two optional features. It is not reachable through an MCP server.

  • Scrape posts from a profile timeline or a single post URL
  • Resolve every repost and quote into the original post it shares, with the original author's audience stats
  • Filter to amplification only, or by the original author's follower count
  • List the reposters of a post (needs an X session)
  • Export as JSON, CSV, Excel, or query the dataset through the Apify API

πŸ“Š What data does Twitter X Tweets Scraper Scraper - Repost and Quote collect?

Three distinct row/object shapes come out of a run: the post itself, the original post behind a repost or quote, and β€” opt-in β€” the accounts that reposted it.

Data TypeKey FieldsJSON Field Names
Poststext, engagement counts, author profile, media, poll, link carddescription, likes, reposts, quotes, bookmarks, views, followers, is_blue_verified, photos, videos, poll, link_preview
Original posts (repost/quote source)the shared post's own text and counts, plus the real author's audienceoriginal_post.text, original_post.likes, original_post.author_username, original_post.author_followers, original_post.author_bio
Reposters (opt-in, needs a session)handle, audience size, bio, badge, account agehandle, followers, is_blue_verified, account_created_at, post_reposts_declared, post_reposters_collected

Need more X (Twitter) data?

If you need reply-thread structure β€” replies and quotes returned as their own child rows with parentId, reply depth and per-thread roll-ups β€” the account also publishes Twitter (X.com) Tweets & Profiles Scraper, which walks a profile's conversation tree instead of resolving amplification. Both are built on the same base row contract, so the shared columns line up field for field.


πŸ†š How does Twitter X Tweets Scraper Scraper - Repost and Quote differ from the official X API?

The official X API requires a developer account and API keys, and represents a repost or quote as a reference to another tweet id rather than the content itself. This Actor requires neither and resolves the shared post inline.

FeatureOfficial X APITwitter X Tweets Scraper Scraper - Repost and Quote
Access setupDeveloper account and API keys; current access tiers and pricing are published at developer.x.comNo account, no API key β€” enter handles or post URLs and click Start
Repost/quote resolutionA tweet object carries a referenced_tweets reference; reading the referenced post's text, counts and author is a separate call/expansionResolved in the same response β€” original_post ships inline on the row
Amplification filteringNot a built-in parameter β€” the caller fetches everything and filters client-sideonlySharedPosts and minOriginalAuthorFollowers filter during the run
Reposter rosterNo public endpoint lists the accounts that reposted a given postlistReposters returns them as reposter child rows (needs an X session)
Setup timeApplication/approval, key management, client library integrationMinutes β€” no code required to start a run
Output stabilityRaw API JSON shaped by the current API versionA flattened, documented contract shared across the whole actor family

Reach for the official API when you're building an X-native app that also needs to post, follow or manage the account it authenticates as. Reach for this Actor for read-only, bulk collection of amplification data across many accounts, without touching a developer console.


🎯 Why do developers and teams scrape X (Twitter)?

πŸ€– For AI engineers and agent builders

An amplification signal β€” share_type plus original_post.author_followers β€” is a feature most X datasets don't carry. An agent tool can call this Actor with a watchlist of accounts, keep only share_type != "original" rows, and use the original author's follower count as a weight when ranking which posts matter to a narrative. Because every field is typed JSON, the rows drop straight into a RAG index or a tool-calling loop with no HTML parsing step in between.

πŸ“Š For marketers and brand teams

Turning onlySharedPosts: true on for a brand or competitor account strips its own voice out and leaves exactly what it chooses to repost or quote β€” a direct read on which creators, journalists or peer brands it treats as worth amplifying, without manually scrolling a timeline.

πŸ”¬ For researchers and analysts

The Actor returns only publicly accessible posts and profile fields β€” nothing gated behind a follow request. minOriginalAuthorFollowers lets a study segment amplification by account size (e.g., "which small accounts get boosted by verified large ones"), and the reposter roster gives a concrete, exportable audience for a single post rather than a self-reported total.

πŸ§‘β€πŸ’» For developers building data products

Because repost/quote resolution and the reposter roster are configuration, not extra scraping code, a scheduled run against a list of handles is enough to build an "amplification dashboard" or a creator-scouting product without writing an X GraphQL client.


🧭 How to scrape X (Twitter) posts and reposts (step by step)

  1. Open Twitter X Tweets Scraper Scraper - Repost and Quote on its Apify Console page.
  2. Fill in startUrls β€” the only required field β€” one profile handle, profile URL, numeric user id, or single post URL per line.
  3. Set the filters that matter to you: onlySharedPosts for amplification only, minOriginalAuthorFollowers to screen by audience size, and listReposters plus auth_token/ct0 if you need the reposter roster or the profile's own replies.
  4. Click Start, or launch the same run via apify_client or the Apify API β€” the run log reports scan progress per target as it goes.
  5. Open the dataset once the run finishes: export as JSON, CSV or Excel, or switch to a named view (Posts, Shared originals, Reposters, Media & entities, and more) for a narrower table.

What to do when X changes its structure

The web bearer token and GraphQL query ids are not hardcoded β€” the Actor rediscovers them from X's own client bundle at the start of every run and refuses to run against a stale id rather than fail silently. The row contract (base_row.py) is maintained centrally across the whole actor family, so field names and types on your end don't change when X's frontend does.


πŸ”„ What changed in X (Twitter) scraping recently?

X's public web client changed its logged-out delivery in 2026: the pages that serve posts without a login (x.com/, a profile page, a single post page) now ship a rewritten bundle with zero GraphQL query ids in the main file β€” those ids sit in separately loaded chunks instead, discoverable only by crawling the webpack chunk map (measured against the live site 2026-08-03). Older responsive-web bundles that still carry the ids remain reachable only on login-adjacent pages like /i/flow/login.

Separately, X's official developer API has been reported, across multiple API-tracking sites checked 2026-08-04, to have replaced its flat monthly subscription tiers with pay-per-use credit pricing as the new default for developer signups starting in February 2026, with the older flat tiers held open only for existing subscribers. Neither change affects what this Actor returns β€” the keyless surfaces it scrapes are separate from the official API and are re-verified at the start of every run β€” but both raise the maintenance cost of a homegrown scraper that assumes yesterday's bundle shape or API pricing.


⬇️ Input

ParameterRequiredTypeDescriptionExample Value
startUrlsYesarray of stringsOne target per line: a profile URL (https://x.com/NASA), a handle (NASA or @NASA), a numeric user id, or a single post URL. A post URL returns exactly one row and ignores maxTweets.["NASA"]
resolveSharedPostsNobooleanDefault true. On: a repost/quote row also carries original_post. Off: rows are still labelled share_type, but original_post is null. Nothing extra is fetched either way.true
onlySharedPostsNobooleanDefault false. On: the account's own original posts drop out β€” reposts and quotes only. Keeps reading back until it finds the requested count or has scanned 5Γ— that many (minimum 100); an empty match ends the run FAILED with an accounting row, never a silent empty dataset.false
minOriginalAuthorFollowersNointeger (min 0, max 1000000000)Default 0. Drops shared posts whose original author has fewer followers than this. Above 0 it also drops the account's own posts and quotes X refused to hydrate. Requires resolveSharedPosts on.100000
maxTweetsNointeger (min 1, max 1000)Default 10. Posts to KEEP per profile. With no share filter, the number collected; with a share filter on, the number of MATCHING posts. Single post URLs are unaffected.20
sortOrderNostring, enum: recent (Newest first), oldest (Oldest first, of the posts collected), popular (Most liked first, of the posts collected)Default "recent". Re-orders only the posts already collected in this run β€” does not search further back."recent"
includeRepliesNobooleanDefault false. On: also reads the profile's own replies ("Posts and replies" tab). Requires an X session β€” fails immediately without one, rather than returning a partial timeline.false
listRepostersNobooleanDefault false. Adds reposter child rows per collected post. Requires an X session β€” refuses before spending a request rather than returning an empty roster.false
maxRepostersPerPostNointeger (min 1, max 5000)Default 100. Caps reposter rows collected per post. Only used when listReposters is on.100
auth_tokenNostring (secret)The auth_token cookie value from an x.com browser session. Needed only for includeReplies and listReposters. Stored encrypted, sent only to api.x.com, never written to the dataset or run log.(empty)
ct0Nostring (secret)The ct0 cookie value from the same session; required together with auth_token. Same storage/handling as above.(empty)
proxyConfigurationNoobjectDefault {"useApifyProxy": false}. Off by default β€” X was measured serving this data to a bare Apify datacenter exit. Turning it on rotates to a fresh exit once if a request fails before any row was saved.{"useApifyProxy": false}

Example input

{
"startUrls": ["NASA", "https://x.com/Interior/status/1987654321098765432"],
"resolveSharedPosts": true,
"onlySharedPosts": true,
"minOriginalAuthorFollowers": 100000,
"maxTweets": 20,
"sortOrder": "recent",
"includeReplies": false,
"listReposters": false,
"maxRepostersPerPost": 100,
"proxyConfiguration": { "useApifyProxy": false }
}

Common pitfall: setting minOriginalAuthorFollowers above 0 while resolveSharedPosts is off fails the run immediately β€” the follower floor reads a field that only exists once the resolver is on, so either turn the resolver on or leave the floor at 0.


⬆️ Output

Every run writes typed, normalized JSON rows to the default dataset β€” exportable as JSON, CSV, Excel, or any format the Apify API supports. Three row shapes are pushed, all with charged_event_name: "row_result" except accounting rows, which are never charged.

Scraped post (type: "tweet")

{
"type": "tweet",
"id": "1987654321098765432",
"url": "https://x.com/NASA/status/1987654321098765432",
"user_posted": "NASA",
"name": "NASA",
"description": "Full crew aboard, hatch closed. Launch countdown continues.",
"date_posted": "2026-07-30T14:05:00.000Z",
"likes": 15234,
"replies": 412,
"reposts": 3021,
"quotes": 88,
"bookmarks": 640,
"views": 892345,
"lang": "en",
"conversation_id": "1987654321098765432",
"is_repost": true,
"reposted_by": "NASA",
"is_quote": false,
"is_reply": false,
"in_reply_to_user": null,
"in_reply_to_post_id": null,
"is_pinned": false,
"is_verified": true,
"is_blue_verified": true,
"verified_type": "Business",
"followers": 54000000,
"following": 245,
"posts_count": 15234,
"profile_image_link": "https://pbs.twimg.com/profile_images/000/avatar.jpg",
"biography": "Explore the universe and discover our home planet.",
"external_url": "https://www.nasa.gov",
"hashtags": ["Artemis"],
"tagged_users": ["NASAKennedy"],
"photos": null,
"videos": ["https://video.twimg.com/ext_tw_video/000/pu/vid/000.mp4"],
"media": [{"type": "video", "image_url": "https://pbs.twimg.com/000.jpg", "alt_text": null, "width": 1280, "height": 720, "video_url": "https://video.twimg.com/ext_tw_video/000/pu/vid/000.mp4", "duration_ms": 45000, "expanded_url": null}],
"quoted_post": null,
"poll": null,
"link_preview": null,
"input": {"url": "https://x.com/NASA/status/1987654321098765432"},
"share_type": "repost",
"original_post": {
"post_id": "1987650001112223334",
"url": "https://x.com/NASAKennedy/status/1987650001112223334",
"text": "Full crew aboard, hatch closed. Launch countdown continues.",
"date_posted": "2026-07-30T13:40:00.000Z",
"likes": 8021,
"reposts": 3021,
"replies": 210,
"quotes": 40,
"bookmarks": 300,
"views": 502111,
"author_username": "NASAKennedy",
"author_name": "NASA Kennedy",
"author_id": "24581234",
"author_followers": 620000,
"author_is_verified": true,
"author_bio": "News from America's Spaceport.",
"media_count": 1
}
}

share_type is always present (original, repost or quote); original_post is null on an original post and on every row when resolveSharedPosts is off. The quoted_post object (the base actor family's own contract, present whenever the post itself quotes something) ships its own eight keys, including the shipped, intentionally misspelled data_posted key.

Reposter (type: "reposter", only when listReposters is on)

{
"type": "reposter",
"id": "3345566778",
"handle": "spacefan22",
"name": "Space Fan",
"profile_url": "https://x.com/spacefan22",
"followers": 3400,
"following": 512,
"posts_count": 9021,
"is_blue_verified": false,
"verified_type": null,
"biography": "Rockets, orbits, and coffee.",
"location": "Houston, TX",
"account_created_at": "2012-03-04T00:00:00.000Z",
"is_protected": false,
"profile_image_link": "https://pbs.twimg.com/profile_images/111/avatar.jpg",
"post_id": "1987654321098765432",
"post_url": "https://x.com/NASA/status/1987654321098765432",
"post_author": "NASA",
"post_reposts_declared": 3021,
"post_reposters_collected": 2874,
"input": {"url": "https://x.com/NASA/status/1987654321098765432"}
}

post_reposts_declared is X's own repost counter for that post; post_reposters_collected is how many accounts its Retweeters timeline actually served β€” they differ because protected and suspended accounts stay in the counter but are never served.

Accounting row (type: "error", never charged)

{
"type": "error",
"id": null,
"target": "BBCBreaking",
"errorReason": "no_shared_posts",
"message": "20 post(s) were read from this target and none matched the share filters (onlySharedPosts=True, minOriginalAuthorFollowers=0). This account published no qualifying repost or quote in the range scanned.",
"input": {"url": "BBCBreaking"}
}

errorReason values include user_not_found, account_suspended, protected_account, post_not_found, post_unavailable, no_posts_returned, no_shared_posts, auth_required, rate_limited, request_failed. Filter these out of billing or downstream analysis with type != "error".

Dataset views ship pre-built for common slices: πŸ“‹ Posts (default), πŸ” Shared originals, πŸ‘₯ Reposters, πŸ–ΌοΈ Media & entities, πŸ’¬ Quoted posts (base contract), πŸ“Š Polls & link cards, πŸ‘€ Author profile, and ⚠️ Skipped targets.


πŸ†š How does Twitter X Tweets Scraper Scraper - Repost and Quote compare to other X (Twitter) scrapers?

FeatureTwitter X Tweets Scraper Scraper - Repost and QuoteGeneric alternative
Output formatTyped, normalized JSON with a documented, stable schemaβœ…/❌ depends on the tool β€” many return raw HTML or unflattened GraphQL
Repost/quote resolutionOriginal post opened inline as original_post, including the original author's audience stats❌ Most scrapers leave a repost as a truncated reference to the original
Amplification filteringonlySharedPosts and minOriginalAuthorFollowers filter during the run❌ Typically requires post-processing the full dataset yourself
Reposter rosterlistReposters returns the accounts, cross-checked against X's own declared count❌ Not commonly offered β€” X's Retweeters surface needs an authenticated session
Uncharged failuresAccounting rows for a target that returned nothing are never billed❌ or not documented, depending on the tool

If you're building an AI agent or RAG pipeline, the output format row is the decision-maker β€” parsing HTML inside an agent loop is a reliability failure mode, not a feature.


πŸ“ˆ How many results can you scrape with Twitter X Tweets Scraper Scraper - Repost and Quote?

maxTweets caps posts kept per profile at 1,000 (default 10); a single post URL always returns exactly one row regardless of that setting. Pagination walks X's cursor-based timeline in pages of 20 posts, for up to 60 pages per target β€” a hard ceiling in the Actor, not something X enforces. When onlySharedPosts or minOriginalAuthorFollowers is set, the Actor keeps reading further back until it collects the requested number of matching posts or has scanned 5Γ— that many posts (minimum 100), then stops and reports an uncharged accounting row if nothing matched.

maxRepostersPerPost caps the reposter roster at 5,000 per post (default 100), walked in pages of up to 100 across at most 40 pages. There is no separate result cap across multiple startUrls targets β€” each target is scanned independently up to its own maxTweets limit. X's own rate limits, read from the x-rate-limit-* response headers, are the real ceiling on how fast a large run can move; a 429 rotates the guest token and retries once, then waits out a short reset window before failing loudly.


πŸ”Œ Integrate Twitter X Tweets Scraper Scraper - Repost and Quote and automate your workflow

Twitter X Tweets Scraper Scraper - Repost and Quote works with any language or tool that can send an HTTP request, through the Apify API.

REST API integration

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_API_TOKEN>")
run = client.actor("API-Empire/twitter-x-tweets-scraper-scraper-repost-and-quote").call(
run_input={
"startUrls": ["NASA"],
"onlySharedPosts": True,
"minOriginalAuthorFollowers": 100000,
"maxTweets": 20,
}
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item["share_type"], item.get("original_post", {}).get("author_username"))

Works in Python, Node.js, Go, Ruby, cURL β€” any client of the Apify API.

Automation platforms (n8n, Make, LangChain)

Apify's own n8n node and Make module can start this Actor's run and pull its dataset without custom code β€” point either at the Actor API-Empire/twitter-x-tweets-scraper-scraper-repost-and-quote and pass the same input fields shown above. For LangChain-based agents, Apify's ApifyDatasetLoader/ApifyActorsTool integration can call the Actor and load the resulting dataset rows directly into a chain or an agent tool.


Yes β€” this Actor returns only publicly available posts and profile fields; it never accesses protected accounts or content behind a login wall (it fails the target explicitly with protected_account instead). Because profile fields like handle, display name, bio, follower count and account age are personal data under data protection law when tied to an identifiable person, storing or reusing them at scale falls under GDPR (EU/UK) and CCPA (California) β€” you need a lawful basis for collecting and retaining that data, and reposter or author records about identifiable individuals should be handled accordingly. Scraping public data is generally permitted, but X's own Terms of Service govern automated access to the platform separately from data-protection law. Consult legal counsel for commercial use cases involving bulk personal data.


❓ Frequently asked questions

Does this actor work without an X (Twitter) account?

Yes for its core path β€” profile timelines, single post URLs, share_type labelling and the full original_post resolution (including the original author's followers, bio and badge) all run keyless, using a guest token. Only includeReplies and listReposters require an X session (auth_token + ct0 cookies), because X serves those two surfaces an empty HTTP 404 to a logged-out caller.

How often is the scraped data updated?

Every run fetches live from X at request time β€” there is no cache and no stored snapshot reused between runs. Rate-limit headers and post counts are read once per request and reported as read, never smoothed into an average or compared against a previous run.

What happens if a post is deleted or an account is suspended or protected?

The target gets an uncharged accounting row (type: "error") with a typed errorReason β€” post_not_found, post_unavailable, account_suspended or protected_account β€” and a human-readable message. A quote whose original X refused to hydrate keeps share_type: "quote" and fills original_post.post_id, leaving every other original-post field null rather than guessing.

Can I scrape private or protected X accounts?

No. Only publicly accessible posts and profiles are returned; a protected account resolves to errorReason: "protected_account" with no rows for that target.

How much does it cost to run?

Pricing is pay-per-result: a charged row_result event fires for every post row and every reposter row. Accounting/error rows for a target that returned nothing are never charged. Check the Actor's Pricing tab on the Apify Console for the current rate per event.

Does Twitter X Tweets Scraper Scraper - Repost and Quote work for AI agent workflows and LLM pipelines?

Yes. It is callable as an HTTP endpoint by any agent framework through the Apify API, and every row is typed JSON with stable field names β€” no HTML, no selectors, no parsing step before passing a row to an LLM or a vector store.

How does it handle X's anti-bot system?

It activates a fresh guest token per run for the keyless surfaces, and rediscovers the current web bearer token and GraphQL query ids from X's own client bundle at the start of every run rather than hardcoding values that go stale. On a request failure it rotates to a fresh Apify Proxy exit once before retrying; on an HTTP 429 it first rotates the guest token (keyless buckets reset with a new token), then waits out a short reset window if one is given, before failing loudly with rate_limited.

How does it compare to scraping X (Twitter) yourself?

A homegrown scraper has to track X's GraphQL query ids and bearer token by hand, treat a retweet's structural placeholder counts (X ships 0 likes/replies/quotes on the retweet wrapper itself) as real, and build reposter-roster pagination against an endpoint that keeps handing back a live cursor after the roster is actually exhausted. This Actor's row builder resolves the real original post and its real counts instead of the wrapper's zeros, and stops the reposter walk only after two consecutive empty pages.

Does it return data in a format LLMs can use directly?

Yes. Typed, normalized JSON with stable field names across every row type β€” pass it directly into an LLM context window, index it into a vector store, or route it through an agent tool without a parsing step.

Can I use it without managing proxies?

Yes. proxyConfiguration defaults to off β€” X was measured serving this data to a bare Apify datacenter exit. Turn Apify Proxy on only if you want a different exit or expect to run at high volume; the Actor rotates to a fresh exit once on a failed request.

What happens when X changes its structure or blocks the scraper?

The Actor is maintained, and the output schema stays stable β€” field names and types on your end don't change when X's frontend does. The bearer token and query ids are rediscovered at runtime rather than hardcoded, so a frontend change is a maintenance event on this Actor's side, not a silent breakage on yours. No specific turnaround time is promised.


πŸ’¬ Your feedback

Found a bug, or a field that behaves differently than documented here? We want to know. Open an issue from the Actor's page on the Apify Console (the Issues tab), or message the developer directly through the Console β€” both reach the team maintaining this actor family.