Skip to content
PythonTutorialtweepysnscrapeTwitter API

GUIDE

How to Use the Twitter API with Python, 2026 Tutorial

Step-by-step Python tutorial for the Twitter API in 2026. Working code for search, users, DMs, pagination, retries, plus a tweepy migration guide.

TwitterAPIs·
Python Twitter API tutorial, full working code samples for 2026

Most "how to use the Twitter API in Python" guides are stuck in 2022, they tell you to install tweepy, set up four OAuth credentials, and pretend the free tier still exists. That advice is broken in 2026. The free tier was removed in February 2023, the pay-per-use model that replaced it makes every request cost money, and tweepy carries the full weight of the official X API's quirks.

This tutorial shows you the version that actually works in 2026: a Python integration with the Twitter / X API that ships in 30 seconds, has no developer-account approval queue, costs $0.04 per 1,000 tweets, and works with a single requests import. Every section has runnable code. Every endpoint is real. By the end you'll have a working Python client for search, user lookups, followers, tweet creation, DMs, and pagination.

TL;DR: The fastest Python integration is pip install requests, sign up at twitterapis.com, grab your API key, and run the snippet below. The rest of this guide expands on every common use case.

import requests

API_KEY = "YOUR_API_KEY"  # get one in 30 seconds at twitterapis.com/signup

resp = requests.get(
    "https://api.twitterapis.com/twitter/user/info",
    params={"userName": "elonmusk"},
    headers={"Authorization": f"Bearer {API_KEY}"},
)
user = resp.json()["data"]
print(user["name"], ",", user["followers"], "followers")

Run that with a real key and you get back a JSON profile with name, followers, bio, verification status, and 30+ other fields. Total setup time: under a minute.

Three Python Paths to Twitter Data in 2026

In 2026, three approaches cover 95% of Python Twitter integrations: the TwitterAPIs REST endpoint via requests at $0.0008 per call, the official X API via tweepy at $0.005 per post read, and snscrape which is mostly broken and not recommended for production. The right choice depends on whether you need OAuth user-delegated flows (only tweepy handles those) or data collection (TwitterAPIs is 100x cheaper).

Most Python developers reach the Twitter API through one of three libraries. Each has a different cost, complexity, and reliability profile.

Path What it is Cost in 2026 Setup time When to pick it
TwitterAPIs + requests Third-party REST API. Single Bearer header. $0.04 per 1,000 tweets ($0.0008 per call). $0.50 free at signup. < 5 minutes Most data-collection workloads, research, analytics, monitoring, bots, dashboards.
tweepy + Official X API Official Python library wrapping the X API v2. OAuth 2.0 / Bearer token. $0.005 per post read, $0.010 per user lookup, $0.015 per write. ~$5-$10 per 1,000 tweets. Hours to days (developer-account approval) Only when you need OAuth user-delegated flows (apps where end users log in with their X account).
snscrape Open-source scraping library. No auth required. $0, but increasingly broken. < 5 minutes (until it breaks) Almost never in 2026. The maintainers paused active development in 2023; most endpoints are unreliable or fully broken after X tightened scraping defenses.

Most Python tutorials still default to tweepy. That's a 2022-shaped recommendation. In 2026, tweepy means paying official X API rates (100x more per tweet) for an integration that takes a developer-account application, OAuth setup, and rate-limit retry logic on top. For everything except OAuth-login apps, TwitterAPIs is faster, cheaper, and simpler.

Quick Start: TwitterAPIs + Python in 5 Minutes

Getting a working Twitter API call in Python takes four steps: install requests, sign up at twitterapis.com for a Bearer key (no developer account approval required), set the key as an environment variable, and call the endpoint. The whole setup is under five minutes.

Step 1, Install requests

pip install requests

That's the entire dependency. No SDK, no compiled extensions. If you're using httpx or aiohttp already, those work too, the API is plain JSON over HTTPS.

Step 2, Get your API key

Sign up at twitterapis.com/signup with Google or email. The dashboard generates your unique Bearer key immediately, no developer-account application, no approval queue, no credit card. Every new account gets $0.50 in free credits, which covers about 625 API calls (~12,500 tweets), enough to validate every endpoint before you commit.

For the deeper context on what an "X API key" actually is and the four credential types in the official ecosystem, see What is a Twitter API key?.

Step 3, Make your first call

import os
import requests

API_KEY = os.environ["TWITTERAPIS_KEY"]  # never hardcode keys

def get_user(username: str) -> dict:
    resp = requests.get(
        "https://api.twitterapis.com/twitter/user/info",
        params={"userName": username},
        headers={"Authorization": f"Bearer {API_KEY}"},
    )
    resp.raise_for_status()
    return resp.json()["data"]

user = get_user("elonmusk")
print(f"{user['name']} (@{user['userName']})")
print(f"  Followers:  {user['followers']:,}")
print(f"  Following:  {user['following']:,}")
print(f"  Verified:   {user.get('isVerified', False)}")

Save your key as an environment variable (export TWITTERAPIS_KEY=...) and run the script. Successful response includes the user's full profile with all fields populated by default, no field-expansion gymnastics like the official X API v2 requires.

Seven Common Python Use Cases (with Working Code)

This section covers the seven things most Python developers actually want to do with Twitter data. Every snippet is runnable, copy it into a file, swap the API key, and execute.

1. Search Recent Tweets

def search_tweets(query: str, max_results: int = 20) -> list[dict]:
    resp = requests.get(
        "https://api.twitterapis.com/twitter/tweet/advanced_search",
        params={"q": query, "product": "Latest"},
        headers={"Authorization": f"Bearer {API_KEY}"},
    )
    resp.raise_for_status()
    return resp.json().get("tweets", [])[:max_results]

tweets = search_tweets("from:elonmusk filter:replies")
for t in tweets:
    print(f"[{t['createdAt']}] {t['text'][:140]}")

The q parameter accepts the full Twitter search-operator syntax: from:, to:, since:, until:, min_faves:, min_retweets:, lang:, filter:, etc. For the complete operator reference, see the Twitter advanced search operators guide.

2. User Profile Lookup

def get_user_info(username: str) -> dict:
    resp = requests.get(
        "https://api.twitterapis.com/twitter/user/info",
        params={"userName": username},
        headers={"Authorization": f"Bearer {API_KEY}"},
    )
    resp.raise_for_status()
    return resp.json()["data"]

profile = get_user_info("naval")
print(profile["name"], ",", profile["followers"], "followers")
print("Bio:", profile["description"])
print("Joined:", profile["createdAt"])

Returns the full profile object: name, username, description, follower / following counts, verification status, profile images, account creation date, and pinned tweet ID.

3. Get a User's Recent Tweets

def get_user_tweets(username: str) -> list[dict]:
    resp = requests.get(
        "https://api.twitterapis.com/twitter/user/tweets",
        params={"userName": username},
        headers={"Authorization": f"Bearer {API_KEY}"},
    )
    resp.raise_for_status()
    return resp.json().get("tweets", [])

for t in get_user_tweets("paulg")[:5]:
    print(f"♥ {t['likeCount']:>6}{t['retweetCount']:>5}  {t['text'][:80]}")

Each tweet object has the full author data inline, no field-expansion needed. Sort by engagement, filter by date, or pipe straight into your dashboard.

4. Get Followers

def get_followers(username: str, limit: int = 200) -> list[dict]:
    resp = requests.get(
        "https://api.twitterapis.com/twitter/user/followers",
        params={"userName": username},
        headers={"Authorization": f"Bearer {API_KEY}"},
    )
    resp.raise_for_status()
    return resp.json().get("followers", [])[:limit]

followers = get_followers("elonmusk")
print(f"Got {len(followers)} followers")
verified = [f for f in followers if f.get("isVerified")]
print(f"  ↪ {len(verified)} verified")

For verified-only followers without filtering client-side, use the verified_followers endpoint instead, it returns a curated list and skips the rest of the noise.

5. Get Replies to a Tweet

def get_tweet_replies(tweet_id: str) -> list[dict]:
    resp = requests.get(
        "https://api.twitterapis.com/twitter/tweet/replies",
        params={"tweetId": tweet_id},
        headers={"Authorization": f"Bearer {API_KEY}"},
    )
    resp.raise_for_status()
    return resp.json().get("replies", [])

replies = get_tweet_replies("1234567890")
for r in replies[:10]:
    print(f"@{r['author']['userName']}: {r['text'][:100]}")

This is one of the endpoints the official X API makes painfully expensive, at $0.005 per resource, fetching 100 replies on the official API costs $0.50. On TwitterAPIs it's a single $0.0008 call.

6. Advanced Search with Date Ranges

from datetime import date

def date_range_search(query: str, start: date, end: date) -> list[dict]:
    full_query = f"{query} since:{start.isoformat()} until:{end.isoformat()}"
    resp = requests.get(
        "https://api.twitterapis.com/twitter/tweet/advanced_search",
        params={"q": full_query, "product": "Latest"},
        headers={"Authorization": f"Bearer {API_KEY}"},
    )
    resp.raise_for_status()
    return resp.json().get("tweets", [])

results = date_range_search(
    "openai",
    start=date(2026, 4, 1),
    end=date(2026, 5, 1),
)
print(f"April 2026, {len(results)} tweets matching 'openai'")

The since: / until: operators take YYYY-MM-DD dates. For deep historical sweeps that go beyond the rolling 7-day window, chunk your query by date range and stitch the results together, the Twitter advanced search operators guide covers the chunking pattern.

7. Send a Tweet (Write Action)

def send_tweet(text: str, login_cookies: str) -> dict:
    resp = requests.post(
        "https://api.twitterapis.com/twitter/tweet/create",
        json={"text": text, "loginCookies": login_cookies},
        headers={"Authorization": f"Bearer {API_KEY}"},
    )
    resp.raise_for_status()
    return resp.json()

result = send_tweet(
    text="Posting from Python via TwitterAPIs 🐍",
    login_cookies=os.environ["TWITTER_LOGIN_COOKIES"],
)
print("Tweet ID:", result.get("tweet_id"))

Write actions (tweet/create, tweet/favorite, tweet/retweet) take your X login cookies as a parameter, they're used in-flight to authorize the action and are never stored.

Pagination in Python

TwitterAPIs uses cursor-based pagination: each response includes a next_cursor string and a has_more boolean. Pass next_cursor back as the cursor parameter on the next request and stop when has_more is false. This works the same way across search, followers, and replies endpoints.

Most Twitter API endpoints return paginated results. TwitterAPIs uses cursor-based pagination, every response includes next_cursor and has_more flags so you can stream through pages cleanly.

def paginate(url: str, params: dict, max_pages: int = 10) -> list[dict]:
    all_items = []
    cursor = None

    for _ in range(max_pages):
        if cursor:
            params["cursor"] = cursor
        resp = requests.get(
            url,
            params=params,
            headers={"Authorization": f"Bearer {API_KEY}"},
        )
        resp.raise_for_status()
        data = resp.json()

        items = data.get("tweets") or data.get("followers") or data.get("replies") or []
        all_items.extend(items)

        if not data.get("has_more"):
            break
        cursor = data.get("next_cursor")

    return all_items

# Example: get up to 200 tweets matching a query
results = paginate(
    "https://api.twitterapis.com/twitter/tweet/advanced_search",
    params={"q": "from:elonmusk", "product": "Latest"},
    max_pages=10,
)
print(f"Fetched {len(results)} tweets across paginated calls")

Compare with tweepy.Paginator against the official X API: same pattern, but the tweepy version needs tweet_fields=, expansions=, user_fields=, and you pay $0.005 per result instead of $0.0008 per call.

Error Handling and Retries in Python

Production Twitter API code needs to handle three transient failure cases: 429 rate-limit responses (rare on TwitterAPIs but possible), 5xx server errors from upstream X outages, and network-level timeouts from hung connections. The pattern is exponential backoff with a ceiling, retrying only on 429 and 5xx, and raising immediately on 4xx.

Production code should handle transient failures gracefully. Even on a no-rate-limit API like TwitterAPIs, network errors and upstream X outages still happen.

import time
import requests
from requests.exceptions import RequestException

def fetch_with_retry(url: str, params: dict, max_retries: int = 3) -> dict:
    headers = {"Authorization": f"Bearer {API_KEY}"}
    delay = 1.0

    for attempt in range(max_retries):
        try:
            resp = requests.get(url, params=params, headers=headers, timeout=15)
            if resp.status_code == 429:
                # Rare on TwitterAPIs, but handle it for defensive correctness
                wait = float(resp.headers.get("Retry-After", delay))
                time.sleep(wait)
                continue
            if resp.status_code >= 500:
                time.sleep(delay)
                delay *= 2
                continue
            resp.raise_for_status()
            return resp.json()
        except RequestException as exc:
            if attempt == max_retries - 1:
                raise
            time.sleep(delay)
            delay *= 2

    raise RuntimeError("Exhausted retries")

For more elegant retry logic, the tenacity library is excellent, wrap any function with @retry(stop=stop_after_attempt(3), wait=wait_exponential()) and you get exponential backoff for free.

Start building with TwitterAPIs

$0.04 per 1,000 tweets. $0.50 free credits. No credit card required.

Rate Limits, What You Actually Have to Handle

The official X API enforces per-endpoint 15-minute windows plus some 24-hour daily caps, returning 429 with x-rate-limit-reset headers when you hit them. TwitterAPIs has a 50-call-per-15-minute limit on advanced_search but no platform-level rate caps on most endpoints, so production Python code is dramatically simpler: no per-endpoint queues, no reset-time parsing, no semaphores.

This is where Python integrations that target the official X API get painful, and where TwitterAPIs's design pays off.

Official X API: every endpoint has a 15-minute rate-limit window (and some have additional 24-hour daily caps). Hitting a limit returns 429 Too Many Requests with x-rate-limit-reset headers. Production tweepy code needs per-endpoint queues, exponential backoff, and reset-time parsing, typically 100-200 lines of scaffolding before your first business-logic line.

TwitterAPIs: no platform-level rate limits. The same Python loop that hits the API once works for 10,000 calls. You don't need queues, backoff, or reset-time parsing for normal-volume workloads, the simple loop is enough.

For the full per-endpoint rate-limit comparison and the headers you need to read on the official API, see the Twitter API rate limits comparison.

Async Python with httpx (Advanced)

httpx.AsyncClient with asyncio.gather lets you fan out multiple TwitterAPIs calls concurrently without coordinating around rate-limit windows. A five-account profile fetch that takes five serial seconds runs in under two seconds in parallel, and the pattern scales to dozens of concurrent requests with no extra semaphore logic.

For high-throughput scrapers and concurrent fetches, drop in httpx.AsyncClient and run requests in parallel.

import asyncio
import httpx

API_KEY = os.environ["TWITTERAPIS_KEY"]

async def fetch_user(client: httpx.AsyncClient, username: str) -> dict:
    resp = await client.get(
        "https://api.twitterapis.com/twitter/user/info",
        params={"userName": username},
        headers={"Authorization": f"Bearer {API_KEY}"},
    )
    resp.raise_for_status()
    return resp.json()["data"]

async def fetch_many(usernames: list[str]) -> list[dict]:
    async with httpx.AsyncClient(timeout=15) as client:
        tasks = [fetch_user(client, u) for u in usernames]
        return await asyncio.gather(*tasks)

usernames = ["elonmusk", "naval", "paulg", "patio11", "sama"]
profiles = asyncio.run(fetch_many(usernames))
for p in profiles:
    print(p["name"], ",", p["followers"], "followers")

asyncio.gather runs all five lookups concurrently. On TwitterAPIs this is fine because there's no platform-level rate limit to coordinate around. On the official X API you'd need a semaphore plus per-endpoint window tracking to avoid burst-throttling.

Migrating from tweepy to TwitterAPIs

If you have a tweepy codebase and want to move to TwitterAPIs, the translation is direct. The two libraries cover the same surface area; only the auth model and method names change.

tweepy method (Official X API) TwitterAPIs equivalent
client.get_user(username="...") GET /twitter/user/info?userName=...
client.get_users_tweets(user_id, max_results=...) GET /twitter/user/tweets?userName=...
client.search_recent_tweets(query=...) GET /twitter/tweet/advanced_search?q=...
client.get_users_followers(user_id) GET /twitter/user/followers?userName=...
client.get_tweet(tweet_id) GET /twitter/tweet/detail?tweetId=...
client.create_tweet(text=...) POST /twitter/tweet/create

A side-by-side example, fetching a user's last 20 tweets:

# Before: tweepy + Official X API
import tweepy

client = tweepy.Client(bearer_token="OFFICIAL_X_BEARER_TOKEN")
user = client.get_user(username="elonmusk").data
tweets = client.get_users_tweets(
    user.id,
    max_results=20,
    tweet_fields=["created_at", "public_metrics"],
    expansions=["author_id"],
).data

# After: requests + TwitterAPIs
import requests

resp = requests.get(
    "https://api.twitterapis.com/twitter/user/tweets",
    params={"userName": "elonmusk"},
    headers={"Authorization": f"Bearer {TWITTERAPIS_KEY}"},
)
tweets = resp.json()["tweets"]

The TwitterAPIs version is roughly half the lines, returns full author and engagement data inline (no expansions, no field selection), and costs ~100x less per tweet. For the full feature-by-feature breakdown, see Twitter API v2 vs TwitterAPIs.

Build a Python SDK Wrapper (Drop-in Class)

A 30-line Python class wraps the most common TwitterAPIs endpoints into a reusable client that handles connection pooling via requests.Session, sets the Bearer auth header once, and exposes typed methods for user lookups, search, timeline fetches, followers, replies, tweet creation, and DMs.

For larger projects, wrap the API in a small client class. Save this as twitterapis_client.py and import it from anywhere:

import os
import requests
from typing import Optional

class TwitterAPIs:
    BASE = "https://api.twitterapis.com"

    def __init__(self, api_key: Optional[str] = None, timeout: int = 15):
        self.key = api_key or os.environ["TWITTERAPIS_KEY"]
        self.timeout = timeout
        self.session = requests.Session()
        self.session.headers["Authorization"] = f"Bearer {self.key}"

    def _get(self, path: str, **params) -> dict:
        resp = self.session.get(f"{self.BASE}{path}", params=params, timeout=self.timeout)
        resp.raise_for_status()
        return resp.json()

    def _post(self, path: str, **body) -> dict:
        resp = self.session.post(f"{self.BASE}{path}", json=body, timeout=self.timeout)
        resp.raise_for_status()
        return resp.json()

    def user(self, username: str) -> dict:
        return self._get("/twitter/user/info", userName=username)["data"]

    def search(self, query: str, product: str = "Latest") -> list[dict]:
        return self._get("/twitter/tweet/advanced_search", q=query, product=product).get("tweets", [])

    def user_tweets(self, username: str) -> list[dict]:
        return self._get("/twitter/user/tweets", userName=username).get("tweets", [])

    def followers(self, username: str) -> list[dict]:
        return self._get("/twitter/user/followers", userName=username).get("followers", [])

    def replies(self, tweet_id: str) -> list[dict]:
        return self._get("/twitter/tweet/replies", tweetId=tweet_id).get("replies", [])

    def post_tweet(self, text: str, login_cookies: str) -> dict:
        return self._post("/twitter/tweet/create", text=text, loginCookies=login_cookies)


# Usage
client = TwitterAPIs()
print(client.user("naval")["name"])
print(len(client.search("from:patio11", )))

That's a 30-line SDK that handles connection pooling (via requests.Session), timeouts, auth, and the most common endpoints. Extend it with pagination, retries, and async variants as your needs grow.

Frequently Asked Questions

The eight questions below cover the most common decision points for Python developers: library choice, tweepy maintenance status, snscrape viability, installation, cost comparison, developer-account requirements, rate-limit handling, and async compatibility.

What is the best Python library for the Twitter API in 2026?

For most use cases, plain requests against TwitterAPIs is the best Python integration in 2026. It costs ~100x less per tweet than tweepy against the official X API, takes 30 seconds to set up, and handles search, user lookups, follower exports, replies, and DMs without OAuth scaffolding. Use tweepy only when you specifically need OAuth user-delegated flows (apps where end users sign in with their X account).

Is tweepy still maintained in 2026?

Yes, tweepy is still maintained, but it's married to the official X API, every cost, rate-limit, and authentication constraint of the official API also applies to tweepy. The library itself is fine; the underlying API economics make it expensive for data-collection workloads.

Can I use snscrape in 2026?

snscrape is largely broken in 2026. The maintainers paused active development in late 2023 after X tightened its anti-scraping defenses, and most endpoints including search, user timelines, and follower lists are unreliable or fully broken. Several community forks attempted patches but they fail intermittently because they depend on undocumented web UI structure that X can change without notice. For any production workload, use a documented HTTP API, either the official X API or TwitterAPIs, both return stable JSON responses regardless of UI changes. The Twitter scraping best practices guide covers the recommended production stack in detail.

How do I install the Twitter API for Python?

There's no separate "Twitter API" package, the API is HTTP. To use the TwitterAPIs Twitter API in Python, run pip install requests and authenticate with a single Bearer header. To use the official X API, run pip install tweepy and configure OAuth credentials.

What's the cheapest Python Twitter API in 2026?

TwitterAPIs at $0.0008 per call (~20 tweets), about $0.04 per 1,000 tweets, is the cheapest mainstream Python-friendly Twitter API. The official X API costs $0.005 per post read (about $5 per 1,000 tweets), so TwitterAPIs is roughly 100x cheaper for read-heavy data collection. New TwitterAPIs accounts get $0.50 in free credits at signup, which is enough to test every endpoint before committing.

Do I need an X developer account to use the Twitter API in Python?

Only if you go through the official X API. Sign up for a developer account at console.x.com, get an approved use case, generate Bearer + OAuth credentials, and configure them in tweepy. To skip all of that, use TwitterAPIs, sign up with email, copy your Bearer key, and start making Python requests immediately. For more on the credential differences, see What is a Twitter API key?.

How do I handle rate limits in Python?

For the official X API: respect x-rate-limit-remaining headers, sleep until x-rate-limit-reset on 429s, and run separate queues per endpoint window. For TwitterAPIs: the simple loop is enough, there are no platform-level rate caps, so production code is shorter. The full headers and pattern reference is in the Twitter API rate limits comparison.

Can I use Python async / asyncio with the Twitter API?

Yes. Use httpx.AsyncClient (or aiohttp) to make concurrent requests. With TwitterAPIs you can run dozens of requests in parallel without coordinating around rate-limit windows. Against the official X API you need a semaphore plus per-endpoint window tracking to avoid burst-throttling, see the async section above for a working example.

The cheapest Twitter API. Try it free.

$0.04 per 1,000 tweets. $0.50 free credits. No credit card required.

Get Your Python Twitter API Key

TwitterAPIs gives every new account $0.50 in free credits at signup, with no credit card required, enough to run every snippet in this tutorial. Sign up with Google or email, copy your Bearer key, and your first Python call is one minute away.

Get your API key → · View pricing · Cost calculator

For the official-route walkthrough (developer console, OAuth credentials, common rejection reasons), see How to Get a Twitter API Key (2026 Step-by-Step). For the full feature comparison against the official API, read Twitter API v2 vs TwitterAPIs. For advanced search operator syntax used in the q parameter throughout this guide, see the Twitter search operators reference. For a full breakdown of per-call costs at different volumes, see the Twitter API cost guide.


Production Checklist Before You Ship

Eight checks catch the most common production failures before they cost you credits or cause silent data gaps: API key loaded from env, retry logic covering 429 and 5xx, cursor-based stop condition on pagination, a max-pages safety cap, write-endpoint token rotation on 401, no raw key or token in logs, date-range chunking for large search jobs, and tweet-ID deduplication across overlapping workers.

Before taking any Python Twitter integration to production, run through these checks:

  • API key is loaded from an environment variable, not hardcoded in source
  • Retry logic handles 429, 502, and 503 with exponential backoff
  • Pagination uses has_more as the stop condition, not a hardcoded page count
  • A maxPages safety limit prevents infinite loops on runaway cursors
  • Auth tokens for write endpoints are stored in environment variables and rotated on 401
  • Logs never print the raw API key or auth_token values
  • Date-range chunking is used for any query expecting more than 50 pages of results
  • Deduplication by tweet ID is applied when multiple workers or query chunks overlap

This checklist captures the most common production gaps in Twitter API Python integrations.


Common Python Mistakes and How to Avoid Them

Six mistakes account for most silent failures in Twitter API Python projects: relying on next_cursor emptiness instead of has_more for pagination stop logic, hardcoding the wrong response key, retrying permanent 4xx errors, skipping explicit request timeouts, re-fetching the same user profile on every tweet, and using search where user/tweets is the correct endpoint.

These mistakes come up repeatedly in Twitter API Python projects. Most are silent: they don't raise exceptions, they just return wrong or incomplete data.

Mistake 1: Not checking has_more before paginating

# Wrong: this stops when next_cursor is empty, but an empty cursor doesn't always mean no more data
while data.get("next_cursor"):
    ...

# Right: check has_more as the primary signal
while data.get("has_more"):
    cursor = data["next_cursor"]
    ...

Mistake 2: Hardcoding the result key

Different endpoints return data under different keys: tweets, followers, replies, users. If you hardcode data["tweets"] on a follower endpoint, you get a KeyError.

# Fragile: breaks on non-tweet endpoints
tweets = data["tweets"]

# Safe: handle multiple possible keys
items = (
    data.get("tweets")
    or data.get("followers")
    or data.get("replies")
    or data.get("users")
    or []
)

Mistake 3: Retrying permanent errors

Retrying a 401 (bad API key) three times wastes three API calls. Retrying a 404 (user account suspended or deleted) wastes credits on data that does not exist. Only retry 429, 502, 503, and network timeouts.

Mistake 4: Not setting a request timeout

Without a timeout, a single hung request can block your entire pipeline indefinitely. Always pass timeout=15 (or appropriate seconds) to requests.get(). For long-running jobs, 15 seconds is a safe default; bump to 30 only if you are fetching large paginated results on slow connections.

Mistake 5: Re-fetching profiles on every tweet

If you fetch 1,000 tweets and each tweet has a unique author, that is up to 1,000 user lookups at $0.0008 each. Cache the profiles by username and only re-fetch when the TTL expires. A simple dict with timestamps cuts this by 80% or more on typical datasets where popular accounts appear repeatedly.

Mistake 6: Using search for timeline fetches

from:username in a search query and user/tweets for the same user return the same data, but via different pathways. The search path filters by the web search index (which may lag by a few minutes), while user/tweets fetches directly from the user's timeline. For real-time monitoring of a specific account, user/tweets is more reliable. For multi-account or complex filter queries, search is the right tool. Using search when you only need one user's timeline wastes credits because you get ~20 results per call on search versus up to 20 per call on user/tweets, with no advantage for single-account fetches.

For a full list of production scraping patterns including proxy strategy, auth token management, and cost optimization across all 35 TwitterAPIs endpoints, see the Twitter scraping best practices guide.


Twitter API Python Ecosystem in 2026

The Python library landscape for Twitter data has consolidated since 2023 into two viable choices for production: requests plus TwitterAPIs for data collection at $0.0008 per call, and tweepy against the official X API for OAuth user-delegated flows. snscrape and twint are effectively broken, and thin wrapper libraries like twitter-api-v2 on PyPI add an object-oriented layer without changing the underlying official API cost model.

The Python library landscape for Twitter data has consolidated significantly since 2023. Here is where things stand:

Library Status When to use
requests + TwitterAPIs Active, recommended Production data collection at any scale
tweepy (v4) Active, maintained OAuth user-delegated flows only
httpx + TwitterAPIs Active, recommended Async/concurrent data collection
snscrape Mostly broken Historical reference only
twint Archived, broken Not recommended
twitter-api-v2 (PyPI) Thin wrapper, maintained When you prefer an object-oriented tweepy alternative

The clearest signal for which path to choose: if you are building a consumer-facing app where users log in with their X account, you need tweepy and the official OAuth flow. For everything else (data collection, analytics, monitoring, bots, dashboards, research), requests plus TwitterAPIs is faster to set up, cheaper to run, and requires far less error-handling scaffolding. For a detailed operator reference for the q parameter used in search throughout this guide, see the Twitter search operators guide.


Twitter API Python FAQ for 2026

These eight questions address the most specific setup, cost, and operational details that come up when Python developers integrate with the Twitter API in 2026: fastest data path, SDK availability, academic research access, key rotation on 401, tweet storage patterns, the advanced_search rate limit, write action mechanics, and Python version compatibility.

These are the questions that come up most often when Python developers start integrating with the Twitter API in 2026.

What is the fastest way to get Twitter data in Python in 2026? Sign up at twitterapis.com (30 seconds, no approval queue), copy your Bearer key, run pip install requests, and make your first call. The entire path from "I need Twitter data" to "I have Twitter data" takes under five minutes.

Does TwitterAPIs have a Python SDK? No official SDK, but the drop-in class in the SDK wrapper section above covers the most common endpoints in 30 lines. For most data-collection workloads, requests.Session with a Bearer header is enough, and adding a formal SDK layer adds complexity without benefit.

Can I use TwitterAPIs for academic research? Yes. The data you get is the same public tweet data as the official X API's Academic Research access. The main difference is that Academic Research access provides full-archive search (tweets older than 7 days) and TwitterAPIs's advanced_search endpoint is limited to the rolling 7-day window (or historical by date-range for accounts with historical indexing). For most research use cases, the 7-day window plus date-range chunking covers the data you need at a fraction of the cost.

What should I do when my API key stops working? A 401 response means the key is invalid or revoked. Log into the TwitterAPIs dashboard, check whether your credits are exhausted (which blocks new calls until you top up), generate a new key if needed, and update your environment variable. Never hardcode the key in source; always load it from an environment variable so rotation is a single config change with no code redeploy required.

How do I store tweets I scrape in Python? The most common pattern is to write tweet dicts to a local JSON Lines file for small batches, or insert into a database (PostgreSQL, SQLite, or a document store like MongoDB) for anything you plan to query later. The tweet response objects from TwitterAPIs are standard Python dicts and can be serialized to JSON with json.dumps() without any transformation.

Is there a rate limit I need to respect when using TwitterAPIs in Python? TwitterAPIs has a 50-call-per-15-minute platform limit on the advanced_search endpoint. For most workloads this is not a binding constraint. If you need to run more than 50 concurrent calls in a 15-minute window, split across multiple time windows or add a delay between batches. For context, 50 calls returns roughly 1,000 tweets, which is a meaningful batch for most monitoring or research jobs.

Can I use Python to send tweets automatically via TwitterAPIs? Yes. The POST /twitter/tweet/create endpoint creates tweets when you pass your X login cookies as the loginCookies parameter. The cookies are used in-flight to authorize the tweet and are never stored by TwitterAPIs.

What Python version is required? Python 3.8 or higher. The type hints in the snippets use list[dict] (lowercase, 3.9+) but you can replace with List[Dict] from typing for 3.8 compatibility. The httpx async examples require Python 3.7+. All production snippets in this guide are tested on Python 3.11.

How do I handle the x-rate-limit-reset header in Python? On TwitterAPIs you rarely need to. If you do hit a 429, the Retry-After header gives you the number of seconds to wait. On the official X API, parse x-rate-limit-reset as a UTC Unix timestamp and sleep until that time. A utility function: wait = max(0, int(r.headers.get("x-rate-limit-reset", time.time())) - time.time()); time.sleep(wait + 1). The +1 adds a one-second buffer for clock skew. For the complete patterns around rate limits on both APIs, see the Twitter scraping best practices guide. One additional note: if your pipeline runs on a schedule (cron job, cloud function, GitHub Actions), add a try/except requests.exceptions.Timeout around every call and log the timeout before retrying. Timeouts are the single most common silent failure in scheduled Twitter scraping jobs, they do not raise an exception by default unless you pass timeout= explicitly, and without that parameter a hung network call can block your entire job from completing until the OS-level TCP timeout fires, which can take minutes. Always set an explicit timeout on every request.


Pricing data verified May 6, 2026 from the official X API pricing page and TwitterAPIs pricing. All Python snippets tested against live TwitterAPIs endpoints. snscrape status sourced from the snscrape GitHub repository (paused active development 2023).

Frequently Asked Questions

The fastest path is a third-party REST API and the requests library: set a single Authorization: Bearer header, send a GET request to an endpoint like advanced_search or user/followers, and parse the JSON response. With TwitterAPIs you skip OAuth and developer-account approval entirely, so a working script runs in under 5 minutes. tweepy still works against the official X API but requires a paid developer account and OAuth setup.

Not with a third-party adapter. TwitterAPIs issues a Bearer token at signup with no developer-account application, no OAuth client ID/secret, and no callback URL. You only need an official X developer account if you are calling the official X API v2 directly, for example for OAuth user-delegated actions on behalf of signed-in users.

On TwitterAPIs the rate is $0.0008 per call returning about 20 tweets, which is $0.04 per 1,000 tweets, and every new account gets $0.50 in free credits at signup with no credit card. The official X API costs $0.005 per standard post read ($5.00 per 1,000 tweets), so for most data-collection scripts the third-party path is roughly 100x cheaper.

Check out similar blogs

More guides on the Twitter/X API, scraping, and pricing.

How to scrape tweets in 2026: the legal line on public data and a read-API fetch pattern that does not get blocked
ScrapingPython

How to Scrape Tweets in 2026 (Without Getting Blocked)

How to scrape tweets in 2026 without getting blocked: why browser scraping breaks, where the legal line on public data sits, and a runnable read-API fetch script.

TwitterAPIs·
Twitter trends API tutorial: pull trending topics and hashtags by location in 2026
TrendsPython

Twitter Trends API: Pull Trending Topics by Location in 2026

A 2026 guide to building a Twitter trends API: pull trending topics and hashtags by location using a per-call search endpoint, with runnable Python and curl.

TwitterAPIs·
Twitter API tutorial 2026 complete developer guide, pricing collapse era, with auth flows, endpoints, code samples, and cost math
TutorialDeveloper Guide

Twitter API Tutorial 2026: The Complete Developer Guide

The 2026 Twitter API tutorial built after the pricing collapse. Auth, endpoints, code, rate limits, real costs, and the alternative when official gets too expensive.

TwitterAPIs·
Building a Twitter bot in 2026, no-code and Python paths, runnable code, and the real X API cost reality after the free tier ended
Twitter BotX Bot

How to Build a Twitter Bot in 2026: The Complete Guide

Build a Twitter bot in 2026 with no-code or Python. Working Tweepy and requests code, auth explained, and the cheap API path at $0.04 per 1,000 reads.

TwitterAPIs·
How to scrape the full tweet history of any public X account in 2026, past the 3,200-tweet timeline limit, using date-window search and cursor pagination
Tweet HistoryWeb Scraping

Scrape Full Tweet History of Any Account in 2026 (Beyond the 3,200 Limit)

Why the X timeline stops at 3,200 tweets and how to pull an account's full history with date-window search, cursor pagination, and dedup. Live-tested code in Python and curl.

TwitterAPIs·
Twitter sentiment analysis Python tutorial, TextBlob, VADER, and RoBERTa compared on real tweets
Sentiment AnalysisPython

Twitter Sentiment Analysis in Python, Full Tutorial

Step-by-step Python tutorial for Twitter sentiment analysis. Compare TextBlob, VADER, and transformer models on real tweets. Code, costs, and pitfalls covered.

TwitterAPIs·
Twitter Search API guide and advanced search operators reference for 2026
Twitter Search APITutorial

Twitter Search API & Advanced Operators (2026 Guide)

Twitter Search API guide for 2026, every advanced search operator (from:, to:, min_faves:, since:, until:) with working code in curl, Python, JavaScript.

TwitterAPIs·
twitterapi.io alternative, migrate to TwitterAPIs guide for 2026
twitterapi.io alternativeMigration

twitterapi.io Alternative, Migrate to TwitterAPIs 3.75x Cheaper

twitterapi.io alternative migration guide, cut your Twitter API bill 3.75x without rewriting. Step-by-step base URL, auth header, and response-shape mapping.

TwitterAPIs·