---
title: "Scrape Twitter (X) with Python: Tweets, Followers and CSV Export"
description: "Python tutorial: scrape public X (Twitter) tweets and followers with the TwexAPI REST API, page through results and save them to CSV. No browser, proxies or X account."
---

This guide scrapes public X (Twitter) data from Python with plain HTTP requests. You search tweets with advanced search operators, page through the results, export a follower list and save everything to CSV. You don't need a headless browser, proxies or an X account, only a TwexAPI API key.

## Before you start

1. Create an account on [twexapi.io](https://twexapi.io/get-started) to get 20,000 free Credits, about 4,000 reads.
2. Copy your API key from the dashboard and export it:

```bash
export TWEXAPI_KEY="twexapi_xxx"
pip install requests
```

## Search tweets

The [advanced search endpoint](/api-reference/search-endpoints/get-data-page-twitter-advanced-search-page-post) takes a list of `searchTerms`, a `sortBy` of `Latest` or `Top`, and a `next_cursor` for paging. Each page returns up to 20 tweets.

```python
import os
import time

import requests

API = "https://api.twexapi.io"
HEADERS = {"Authorization": f"Bearer {os.environ['TWEXAPI_KEY']}"}


def paginate(path, body, max_items):
    """POST a cursor endpoint until max_items rows or the last page."""
    items, cursor = [], ""
    while len(items) < max_items:
        res = requests.post(f"{API}{path}", headers=HEADERS, json={**body, "next_cursor": cursor}, timeout=30)
        res.raise_for_status()
        page = res.json()
        items += [row for row in page.get("data", []) if row]
        cursor = page.get("next_cursor")
        if not page.get("has_next_page") or not cursor:
            break
        time.sleep(5)  # free Starter plan: 1 request per 5 seconds; paid plans allow 5+ per second
    return items[:max_items]


tweets = paginate(
    "/twitter/advanced_search/page",
    {"searchTerms": ["openai", "lang:en", "min_faves:100", "since:2026-10-01"], "sortBy": "Latest"},
    max_items=200,
)
print(len(tweets), "tweets")
```

`searchTerms` accepts the same operators as the X search box:

| Operator | Example | Meaning |
| :--- | :--- | :--- |
| `from:` | `from:nasa` | Posts by one account |
| `since:` / `until:` | `since:2026-10-01` | Date range |
| `lang:` | `lang:en` | Language |
| `min_faves:` | `min_faves:100` | Minimum likes |
| `-filter:replies` | | Exclude replies |

## Save tweets to CSV

```python
import csv

with open("tweets.csv", "w", newline="", encoding="utf-8-sig") as f:
    writer = csv.writer(f)
    writer.writerow(["tweet_id", "created_at", "user", "likes", "retweets", "text"])
    for t in tweets:
        writer.writerow([
            t.get("tweet_id"),
            t.get("created_at"),
            (t.get("user") or {}).get("screen_name"),
            t.get("favorite_count"),
            t.get("retweet_count"),
            (t.get("text") or "").replace("\n", " "),
        ])
```

`utf-8-sig` keeps emoji and non-Latin text readable when the file is opened in Excel.

## Scrape followers

The [followers endpoint](/api-reference/followers-following-endpoints/get-followers-cursor-apiendpoint-twitter-followers-page-post) uses the same cursor paging, so the `paginate` helper works unchanged.

```python
followers = paginate("/twitter/followers/page", {"screen_name": "nasa"}, max_items=1000)

with open("followers.csv", "w", newline="", encoding="utf-8-sig") as f:
    writer = csv.writer(f)
    writer.writerow(["username", "name", "followers", "location", "bio"])
    for u in followers:
        writer.writerow([u.get("username"), u.get("name"), u.get("followersCount"), u.get("location"), u.get("description")])
```

## Cost

Typical reads cost 5 Credits each, about $0.05 per 1,000 tweets or followers. The 200 tweets and 1,000 followers above cost about $0.06 together. See [pricing](/guides/pricing) for exact rates.

## Why not Selenium, Playwright or twscrape?

Since X shut down guest access in early 2024, browser-based and open-source scrapers need logged-in X accounts and rotating proxies, and they break when X changes its site. An API moves that maintenance off your machine. For a fuller comparison, see [Self-Hosted Twitter Scraper vs TwexAPI](/comparison/scraper-vs-api).

## Next steps

- [Twitter Scraper API overview](https://twexapi.io/twitter-scraper): what you can scrape and how it compares with Apify and the official API.
- [Error handling](/guides/error-handling): retry and back off on `429` and `5xx` responses.
- Collect only public data, and follow privacy law and X's terms for your use case.
