How to Scrape Twitter/X Without an API Key in Python (2026 Guide)
Source: Dev.to
Why use Scweet instead of the official API?
Twitter/X’s official API now starts at $200 / month just to read tweets. The free tier is write‑only – you can post, but you can’t search, pull timelines, or read anything except your own profile.
Scweet bypasses the need for an API key by re‑using the same GraphQL endpoints that the web app uses internally. It sends HTTP requests with the same cookies (auth_token and ct0) that your browser sends, so from X’s perspective it looks like normal browser activity.
- No headless browser, Selenium, or Playwright required.
- Runs locally for $0 (or about $0.30 / 1 000 tweets on the hosted cloud version).
- Works with a single free X account plus an optional proxy.
Twitter/X API pricing (2026)
| Tier | Price (USD) | What you get |
|---|---|---|
| Free | $0 | Write‑only. 500 posts/month. No search, no read access. Only endpoint: GET /2/users/me |
| Basic | $200/month | 15 000 read requests/month. 7 days of search history |
| Pro | $5 000/month | 1 million tweets. Full‑archive search |
| Enterprise | $42 000+/month | Custom, compliance streams |
| Pay‑as‑you‑go (Feb 2026) | ~ $575/month for Basic‑equivalent usage | Not cheaper than the Basic plan |
Sources: TechCrunch, X Developer Community, xpoz.ai pricing breakdown.
Installation
pip install -U scweetObtaining auth_token
- Log in to x.com in Chrome or Firefox.
- Open DevTools (F12) → Application → Cookies →
https://x.com. - Find the
auth_tokencookie and copy its value.
Scweet will automatically bootstrap the ct0 CSRF token from this cookie, so you only need the auth_token. It stays valid for weeks to months; when it expires Scweet raises an AuthError.
Basic usage (Python)
from Scweet import Scweet
s = Scweet(
auth_token="YOUR_AUTH_TOKEN",
proxy="http://user:pass@host:port" # optional but recommended
)
# Search for tweets about Bitcoin from 2025 onward
tweets = s.search(
"bitcoin",
since="2025-01-01",
limit=200,
save=True # writes results to a CSV file
)
print(f"Collected {len(tweets)} tweets")You can change the output format:
s.search("bitcoin", limit=100, save=True, save_format="json") # JSON
s.search("bitcoin", limit=100, save=True, save_format="both") # CSV + JSONEach tweet record includes:
tweet_id,timestamp,text,likes,retweets,comments,tweet_urluser(screen_name, name)image_links- Full raw GraphQL payload (if needed)
CLI usage (no Python code)
scweet --auth-token YOUR_AUTH_TOKEN \
--proxy http://user:pass@host:port \
search "bitcoin" --since 2025-01-01 --limit 200 --saveAvailable endpoints
| Endpoint | Description |
|---|---|
s.search() | Full‑text tweet search |
s.get_profile_tweets(usernames, limit=…) | Timeline of a user’s own tweets |
s.get_followers(usernames, limit=…) | Followers list |
s.get_following(usernames, limit=…) | Following list |
s.get_user_info(usernames) | Bio, follower count, verification status, creation date |
All methods accept a list of usernames, enabling batch requests. Asynchronous variants (asearch(), aget_profile_tweets(), etc.) are also provided.
Multi‑account pooling
For larger scrapes you can rotate several accounts, each with its own proxy:
[
{
"username": "account_1",
"cookies": { "auth_token": "TOKEN_1" },
"proxy": "http://user1:pass1@host1:port1"
},
{
"username": "account_2",
"cookies": { "auth_token": "TOKEN_2" },
"proxy": "http://user2:pass2@host2:port2"
}
]s = Scweet(cookies_file="cookies.json")
tweets = s.search("AI startups", limit=10000, save=True)Scweet stores pool state in SQLite (leases, heartbeats, daily counters, cooldowns) and automatically fails over when an account hits its limit.
Resuming interrupted scrapes
tweets = s.search("AI startups", limit=10000, save=True, resume=True)resume=True picks up exactly where the previous run left off.
Apify actor integration (no code)
Scweet is also available as an Apify actor (altimis/scweet). The hosted version includes a free tier (up to 1 000 tweets/day) and scales to millions at $0.25 / 1 000 tweets.
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("altimis/scweet").call(run_input={
"search_query": "bitcoin",
"max_items": 500,
})
tweets = client.dataset(run["defaultDatasetId"]).list_items().items
print(f"Got {len(tweets)} tweets")This is handy for pipelines, cron jobs, or n8n/Zapier workflows without managing Python dependencies or cookies.
Resources
- GitHub repository: (MIT license, 250+ tests)
- PyPI package:
pip install scweet - Apify actor: (hosted, no‑code)
- Full documentation: