Get Twitter (X) Data in Python (2026 Tutorial)

To get Twitter/X data in Python, install the requests library, get a TwitterAPI.io API key (Google sign-in, no OAuth), and call the REST endpoints with your key in an X-API-Key header — for example GET /twitter/tweet/advanced_search to search tweets or /twitter/user/last_tweets for an account's timeline. This tutorial walks through the whole pipeline with runnable code: search, user data, pagination, rate handling, and saving to pandas or CSV.
If you've used Tweepy with the official API before, this will feel simpler — there's no OAuth dance, no app registration, and no X developer account. You authenticate every request with a single API key in a header, and the endpoints return plain JSON that maps directly to Python dicts. That makes it ideal for data analysis, monitoring scripts, and feeding ML pipelines.
We'll build up from a single search call to a reusable collector with pagination and error handling, then load the results into pandas. Every snippet runs as-is once you drop in your API key (the free starter credits — $1 for new accounts that pass the automatic bot check, one per person and network, no card, expiring after 31 days — are enough for this tutorial).
Step 1 — Set up: install requests and get an API key
You only need one library for the HTTP calls: pip install requests. For analysis, add pandas: pip install pandas. No Twitter-specific SDK is required — the API is plain REST.
Get your API key by signing in with Google at twitterapi.io and copying it from the dashboard. New accounts that pass the automatic bot check include $1 in free credits (one per person and network) with no credit card, expiring after 31 days, which is enough to follow this tutorial.
Keep the key out of your code — read it from an environment variable (e.g. os.environ["TWITTERAPI_KEY"]) so you never commit it. Every request authenticates by sending the key in an X-API-Key header.
Step 2 — Search tweets with advanced_search
The workhorse endpoint is /twitter/tweet/advanced_search. It accepts a query (the same operators you'd type into X search — keywords, from:user, #hashtag, lang:en, date ranges) and a queryType of Latest or Top.
A single GET returns a page of matching tweets plus a next_cursor for the following page. Each tweet object includes the text, author, engagement counts, and timestamps — everything you need for analysis.
Start with one call to confirm your key works, then wrap it in a loop (Step 3) to collect more than one page. The code snippet at the end of this tutorial shows the complete, paginated version.
Step 3 — Paginate to collect more than one page
Each response includes next_cursor. To collect a larger result set, pass that cursor back as the cursor parameter on the next request, and repeat until the cursor is empty (or you hit a self-imposed page limit).
Always cap your loop with a max_pages guard so a broad query doesn't run away and burn credits. For most analyses, a few hundred to a few thousand tweets is plenty — and you control exactly how many calls you make.
Unlike the official API, there's no 15-minute rate window to schedule around. The limit is per second: 0.2 requests/s (one request every 5 seconds) before your first payment, 20 requests/s once you've topped up or bought a plan, 50 on Scale and 500 on Business. If you exceed it you get HTTP 429 with a Retry-After header, so wait that long and continue.
Step 4 — Get user data and timelines
Beyond search, two endpoints cover most user-data needs. /twitter/user/info returns a profile (bio, follower/following counts, verified status, creation date) for a username — useful for enriching or scoring accounts. /twitter/user/last_tweets returns a specific account's recent posts, paginated the same way as search.
For follower analysis, /twitter/user/followers returns an account's followers (paginated). Combine these: search for tweets on a topic, pull each unique author's profile with /twitter/user/info, and you have an enriched dataset for influencer or lead analysis.
All of these take the same X-API-Key header and return JSON you can drop straight into a Python dict or a pandas row.
Step 5 — Load into pandas and save to CSV
Once you've collected a list of tweet dicts, pandas.json_normalize(tweets) flattens nested fields into a DataFrame in one line. From there you can filter, group, compute engagement rates, or plot.
Save with df.to_csv("tweets.csv", index=False) for a portable dataset, or df.to_parquet(...) for a compact columnar file you can reload fast. For ongoing collection, append to a database instead.
This is where the pay-per-call model shines for analysis: you pull exactly the data your notebook needs, when it needs it, without provisioning a monthly quota you may not use.
Error handling and best practices
Check status codes: call r.raise_for_status() and wrap collection in try/except so one bad page doesn't crash a long run. A 401 means the API key is wrong; a 429 means you've exceeded your per-second limit, so wait for the Retry-After value before retrying.
Back off on transient errors: add a short exponential backoff (e.g. retry after 1s, 2s, 4s) so a momentary network blip doesn't lose your run.
Cap pages and log progress: print how many tweets you've collected per page so you can see runaway queries early and stop them.
Keep the key in an env var: never hard-code or commit the API key. Rotate it from the dashboard if it's ever exposed.
Throttle batch jobs: pace requests to your account's limit (one every 5 seconds on free credits, up to 20 per second once paid, more on Scale or Business) and back off on 429.
# Twitter (X) data in Python — full collector with pagination + pandas
# pip install requests pandas
import os, time
import requests
import pandas as pd
API_KEY = os.environ["TWITTERAPI_KEY"] # never hard-code the key
BASE = "https://api.twitterapi.io"
HEADERS = {"X-API-Key": API_KEY}
def _get(url, params, retries=4):
"""GET with Retry-After on 429 and exponential backoff otherwise."""
for attempt in range(retries):
try:
r = requests.get(url, headers=HEADERS, params=params, timeout=30)
if r.status_code == 429 and attempt < retries - 1:
time.sleep(float(r.headers.get("Retry-After", 5)))
continue
r.raise_for_status()
return r.json()
except requests.RequestException:
if attempt == retries - 1:
raise
time.sleep(2 ** attempt)
def search_tweets(query, max_pages=5):
"""Collect tweets matching an advanced-search query, paginated."""
cursor, rows = None, []
for page in range(max_pages):
params = {"query": query, "queryType": "Latest"}
if cursor:
params["cursor"] = cursor
data = _get(f"{BASE}/twitter/tweet/advanced_search", params)
tweets = data.get("tweets", [])
rows.extend(tweets)
print(f"page {page + 1}: +{len(tweets)} (total {len(rows)})")
cursor = data.get("next_cursor")
if not cursor:
break
return rows
def user_profile(username):
"""Fetch a profile for enrichment/scoring."""
return _get(f"{BASE}/twitter/user/info", {"userName": username})
if __name__ == "__main__":
tweets = search_tweets('"machine learning" lang:en', max_pages=3)
df = pd.json_normalize(tweets)
df.to_csv("tweets.csv", index=False)
print(f"saved {len(df)} tweets -> tweets.csv")
print(user_profile("openai"))Questions readers ask
What's the easiest way to get Twitter data in Python?
Use the requests library against a third-party REST API like TwitterAPI.io: get an API key (no OAuth), then GET /twitter/tweet/advanced_search or /twitter/user/last_tweets with the key in an X-API-Key header. The JSON maps directly to Python dicts and into pandas. It's simpler than the official API + Tweepy because there's no OAuth or app-registration step.
Do I still need Tweepy in 2026?
Not for this approach. Tweepy wraps the official X API and its OAuth flow; with a third-party REST API you just use requests and a single API-key header. Tweepy is still fine if you're committed to the official API, but for straightforward data collection plain requests against a pay-per-call API is simpler and avoids the OAuth and developer-account overhead.
How do I paginate through tweets in Python?
Each response from advanced_search (and user/last_tweets) includes a next_cursor field. Pass it back as the cursor parameter on the next request and repeat until it's empty or you reach a max_pages guard. Always cap the loop so a broad query doesn't run away and consume credits — the code sample above shows the pattern.
How do I load tweets into pandas?
Collect the tweet objects into a list, then call pandas.json_normalize(tweets) to flatten nested fields into a DataFrame in one line. From there, df.to_csv('tweets.csv', index=False) saves a portable dataset, or use to_parquet for a compact columnar file. You can then filter, group, and compute engagement metrics with normal pandas.
How do I handle rate limits in Python?
This API has no 15-minute windows like the official API; the limit is per second. It's 0.2 requests/s (one every 5 seconds) before your first payment and 20 requests/s once paid, with 50 on Scale and 500 on Business. On HTTP 429, sleep for the Retry-After value and retry; add a short exponential backoff (1s, 2s, 4s) on other transient errors, and check r.raise_for_status() so a 401 (bad key) surfaces clearly instead of corrupting your dataset.
Is it free to get Twitter data in Python?
To start, yes: TwitterAPI.io's free starter credits ($1 for new accounts that pass the automatic bot check, one per person and network, no card, expiring after 31 days) cover this tutorial and a small prototype. After that it's pay-per-call (~$0.15 per 1,000 tweets, no monthly floor). The official API has no free tier — X bills $0.005 per post read after a $20 starter credit for saving a payment card — so for Python data work the third-party trial is the practical free starting point.
Can I get historical tweets in Python?
Yes — advanced_search supports date-range operators in the query (since:/until: or explicit since_time/until_time params), so you can page back through historical public tweets in Python. For very large historical pulls, paginate in batches and store incrementally so a long run is resumable.
Continue
- Requests — official Python HTTP library documentation
- pandas — official documentation
- X API — official documentation (search operators reference)
- Tweepy vs TwitterAPI.io — Python migration guide →
- Scrape Twitter (X) without the official API →
- API docs — all endpoints + params →
- Pay-per-call pricing + free starter credits →
Stop reading. Start building.
Starter credits cover real testing on real data. Google sign-in, no card, no application queue.
Get an API key