Twitter Scraper | Extract Tweets & Profiles | No API Key avatar

Twitter Scraper | Extract Tweets & Profiles | No API Key

Pricing

from $2.00 / 1,000 result scrapeds

Go to Apify Store
Twitter Scraper | Extract Tweets & Profiles | No API Key

Twitter Scraper | Extract Tweets & Profiles | No API Key

Scrape Twitter/X profiles and tweets without an API key. Batch many accounts in one run, or fetch specific tweets by ID. Tweet text, author, likes, retweets, replies, views, media URLs and timestamps. No keyword search. PPE — pay only for results delivered.

Pricing

from $2.00 / 1,000 result scrapeds

Rating

0.0

(0)

Developer

Web Data Labs

Web Data Labs

Maintained by Community

Actor stats

3

Bookmarked

249

Total users

35

Monthly active users

14 days ago

Last modified

Share

Twitter/X Scraper — Extract Tweets & Profiles Without API Keys

Scrape public Twitter/X profiles and tweets — one account, a list of accounts, or specific tweets by ID — with no API key, no developer account and no login. Structured JSON out, pay only for the rows you receive.

Keyword search is not supported. Anonymous keyword/hashtag search on X is auth-walled and this Actor will not pretend otherwise — see Limitations. If you need keyword search, you need the official X API or a logged-in scraper.


Why Use This Instead of the Official Twitter API?

Official X APIThis Actor
SetupDeveloper account, application, approvalNone — just run it
Cost floorPaid developer tiers onlyPay per result
AuthAPI keys, OAuth, token rotationNone
OutputRaw API JSONFlat, analysis-ready rows

X's official API is locked behind a paid developer account: the legacy Basic tier ($200/mo) is closed to new signups, new developers are metered pay-per-use ($0.005/read, 2M-read cap), and anything above that jumps to Enterprise ($42k+/mo). This Actor reads the same public data.


What You Can Scrape

1. One account

{ "username": "nasa", "maxResults": 50 }

Returns the profile row plus up to 50 tweets.

2. Many accounts in ONE run

{ "usernames": ["nasa", "github", "apify"], "maxResults": 25 }

Each account contributes a profile row and its tweets. One run, one dataset — no orchestration on your side. startUrls accepts full profile URLs instead if that is what your pipeline already produces:

{ "startUrls": [{ "url": "https://x.com/nasa" }, { "url": "https://x.com/github" }] }

3. Specific tweets by ID or URL

{ "tweetIds": ["1519480761749016577", "https://x.com/nasa/status/2084712464466190650"] }

Useful for re-hydrating a list of tweet IDs, refreshing engagement metrics on posts you already track, or pulling the exact posts a webhook told you about. Deleted, protected or non-existent tweets are skipped and never charged.

4. Quoted tweets

{ "username": "elonmusk", "maxResults": 50, "includeQuotedTweets": true }

When a scraped tweet quotes another tweet, the quoted tweet is returned as its own row (type: "quoted_tweet", with quoted_by_tweet_id pointing back at the parent) — full text, author, engagement. It comes from the same API response, so it costs no extra time.


Output

Every row carries a type field: profile, tweet or quoted_tweet.

Tweet row

{
"type": "tweet",
"tweet_id": "2084712464466190650",
"user_id": "11348282",
"user_name": "NASA",
"user_handle": "NASA",
"user_followers": 92241569,
"user_verified": true,
"tweet_text": "LIVE: After 241 days in orbit, @astro_ChrisW returned home on July 26...",
"likes": 1247,
"retweets": 180,
"replies": 112,
"quotes": 13,
"views": 776732,
"bookmarks": 56,
"tweet_url": "https://x.com/NASA/status/2084712464466190650",
"created_at": "Tue Aug 04 18:45:58 +0000 2026",
"is_retweet": false,
"is_reply": false,
"is_quote": false,
"in_reply_to_tweet_id": "",
"in_reply_to_handle": "",
"conversation_id": "2084712464466190650",
"language": "en",
"hashtags": ["Artemis"],
"mentions": ["astro_ChrisW", "Space_Station"],
"links": ["https://www.nasa.gov/live"],
"media_urls": ["https://pbs.twimg.com/media/....jpg"],
"quoted_tweet_id": "",
"quoted_tweet_text": "",
"source": "twitter_api"
}

hashtags, mentions, links, user_followers, user_verified, in_reply_to_* and conversation_id are new in 1.0.19 — no input change needed, they simply appear.

Profile row

{
"type": "profile",
"user_id": "11348282",
"username": "nasa",
"screen_name": "NASA",
"name": "NASA",
"bio": "Making the seemingly impossible, possible. ✨",
"tweets_count": 74293,
"following": 119,
"followers": 92241569,
"likes_count": 16904,
"verified": true,
"profile_image": "https://pbs.twimg.com/profile_images/.../..._400x400.jpg",
"banner_image": "https://pbs.twimg.com/profile_banners/11348282/1775567134",
"location": "Pale Blue Dot",
"website": "http://www.nasa.gov/",
"joined": "Wed Dec 19 20:20:32 +0000 2007",
"listed_count": 97012,
"media_count": 28060,
"profile_url": "https://x.com/NASA",
"source": "twitter_api"
}

username echoes what you passed in; screen_name is X's canonical casing.


Input Parameters

ParameterTypeDefaultDescription
usernamestringelonmuskA single account (with or without @)
usernamesarray[]Several accounts in one run
startUrlsarray[]Profile URLs, e.g. https://x.com/nasa
tweetIdsarray[]Tweet IDs or status URLs
actionstringbothboth, tweets (no profile row), or profile (legacy alias for both)
maxResultsinteger10Max tweets per account. 0 = profiles only
includeQuotedTweetsbooleanfalseEmit quoted tweets as their own rows

Legacy aliases still accepted: maxTweets, limit, count, handle, user, screen_name.


Use Cases

  • Brand monitoring — track what a set of accounts posts, with engagement metrics, on a schedule.
  • Competitor research — batch several competitor handles into one daily run and diff the output.
  • Influencer vettingmaxResults: 0 over a list of handles gives you follower counts, bios and links for a whole shortlist in one cheap run.
  • Engagement refresh — feed yesterday's tweet_ids back in via tweetIds to see how likes/views moved.
  • Content curationincludeQuotedTweets captures the conversation around a post, not just the post.
  • Academic research — flat CSV/JSON export of public timelines without an API application.

Code Examples

Python

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("cryptosignals/twitter-scraper").call(run_input={
"usernames": ["nasa", "github", "apify"],
"maxResults": 25,
"includeQuotedTweets": True,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
if item["type"] == "profile":
print(f'@{item["screen_name"]}: {item["followers"]:,} followers')
else:
print(f' {item["likes"]:>6} likes {item["tweet_text"][:70]}')

Node.js

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('cryptosignals/twitter-scraper').call({
startUrls: [{ url: 'https://x.com/nasa' }, { url: 'https://x.com/github' }],
maxResults: 25,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.table(items.filter(i => i.type === 'tweet').map(({ user_handle, likes, tweet_text }) => ({ user_handle, likes, tweet_text })));

cURL

curl -X POST "https://api.apify.com/v2/acts/cryptosignals~twitter-scraper/runs?token=<TOKEN>" \
-H 'Content-Type: application/json' \
-d '{"usernames":["nasa","github"],"maxResults":20}'

Pricing

Pay-per-event: $0.005 per result. A result is one row in the dataset — one profile, one tweet, or one quoted tweet.

You are charged before a row is delivered, never after. If you set maxTotalChargeUsd on a run, the Actor stops as soon as your cap is reached and tells you how many rows it delivered. You never receive rows you were not charged for, and you are never charged for rows you did not receive. Failed lookups (deleted tweets, suspended accounts, anti-bot pages) cost nothing.

ScenarioResultsCost
One account, 10 tweets11$0.055
10 accounts, profiles only (maxResults: 0)10$0.05
5 competitors × 100 tweets, daily505/day~$2.53/day
Re-hydrating 200 tweet IDs200$1.00

Scheduling & Automation

Use Schedule in the Apify Console for recurring runs, and webhooks to push results downstream (Zapier, Make, your own endpoint, or another Actor). Results export as JSON, CSV, XLSX, XML or RSS.


How It Works

The Actor reads X's public, unauthenticated endpoints using a guest token — the same data any logged-out visitor sees. It carries two generations of X's internal query identifiers and falls through to the second if the first is retired, and it parses both of X's user-object shapes, so a platform-side rotation degrades it rather than breaking it. A public mirror is used as a last-resort fallback for timelines.

A run that retrieves nothing exits with a failed status and a message explaining why. It never finishes green and empty, and it never writes a placeholder row.


Limitations

⚠️ Read this before buying. These are platform restrictions of X's unauthenticated endpoints, not bugs, and no amount of retrying works around them.

  • No keyword or hashtag search. X's SearchTimeline endpoint returns HTTP 404 without a logged-in session, and every public Nitter mirror now answers with an anti-bot challenge. Passing action: "search" fails the run immediately with an explanation rather than returning nothing. Verified 2026-08-05.
  • No followers/following lists, no reply timelines, no media tab, no full conversation threads. All of these endpoints are auth-walled for anonymous clients (HTTP 404), verified against X's current query IDs on 2026-08-05.
  • Small accounts may return 0 tweets. X's unauthenticated timeline endpoint does not serve timelines for very small accounts (roughly under ~10k followers). The profile row is still returned. Accounts at 10k+ followers were verified working.
  • Public data only — no protected accounts, no DMs.
  • Max 10,000 tweets per account per run, paginated automatically.
  • Rate limits — X throttles public endpoints; very large jobs take longer.

📡 More social monitoring actors by this team

PlatformActor
InstagramInstagram Profile Scraper
BlueskyBluesky Scraper
RedditReddit Scraper (Fast)
YouTubeYouTube Scraper
PinterestPinterest Scraper

FAQ

Do I need an X API key or developer account? No. No key, no login, no OAuth.

Can I scrape by keyword or hashtag? No — see Limitations. This used to be advertised and no longer works; the Actor now fails loudly instead of returning an empty dataset.

How do I scrape multiple accounts? usernames: ["a", "b", "c"] or startUrls. One run, one dataset.

Why am I getting 0 tweets for a username? Almost always account size — X does not serve timelines for very small accounts anonymously. You still get the profile row.

Is this legal? It reads publicly available data with no authentication and no circumvention of access controls. You are responsible for complying with X's terms and with data-protection law in your jurisdiction.

What happens when X changes their endpoints? The Actor carries two query-ID generations and two parser shapes, so a rotation usually degrades one path rather than breaking the run. When something does break, it fails loudly instead of billing you for empty rows.

What is pay-per-event pricing? You pay per row delivered, charged before delivery. No monthly fee, no compute-unit maths.