Skip to main content

X-Timeline Scraper

A Python client to scrape tweets from X (formerly Twitter) timelines using a cURL command.


Supported versions pypi downloads License Code style: black

Introduction

This project provides a Python client to scrape tweets from X (formerly Twitter) timelines using a cURL command. It leverages asynchronous programming for efficient data retrieval and includes features for parsing tweet data.

Table of Contents 🗂

Installation ⚙️

To install the X-Timeline Scraper, you can use pip:

pip install xtimeline

Usage ⌨️

The client polls your Following timeline as your own logged-in X session. It needs two cookies from that session:

  1. Log into x.com in your browser.
  2. Open DevTools (F12) → Application (Chrome/Edge) or Storage (Firefox) → Cookies → https://x.com.
  3. Copy the values of auth_token and ct0.

Treat these like a password: they grant full access to your account. They stay valid until you log out of that browser session; client.last_status becomes 401/403 once they expire.

import asyncio
import os
from xclient import XTimelineClient

async def main():
    async with XTimelineClient.from_cookies(
        os.environ["X_AUTH_TOKEN"], os.environ["X_CT0"]
    ) as xc:
        for t in await xc.fetch_tweets():
            print(t.to_markdown())

asyncio.run(main())

If X rotates the timeline's GraphQL query id before a new release ships, pass the current one (from the HomeLatestTimeline request URL in DevTools → Network) via from_cookies(..., query_id="...").

Alternative: a captured cURL command

Instead of cookies you can pass a full captured request, which also picks up any header or feature flag changes X makes. The capture steps are in curl_example.txt; the examples below use this form.

Fetching tweets once

import asyncio
from xclient import XTimelineClient

async def main():
    async with XTimelineClient("curl.txt") as xc:
        tweets = await xc.fetch_tweets()
        for t in tweets:
            print(t.to_markdown())

asyncio.run(main())

Streaming new tweets

import asyncio
from xclient import XTimelineClient

async def main():
    async with XTimelineClient(
        "curl.txt", persist_last_id_path="state/last_id.txt"
    ) as xc:
        async for t in xc.stream():
            print(t.to_markdown())

asyncio.run(main())

By default, stream() now polls every ~30 seconds with built-in jitter (fuzzy interval) so requests do not follow an identical cadence.

# 30s base with +-20% jitter (default)
async for t in xc.stream():
    process(t)

# Custom base interval and jitter
async for t in xc.stream(interval_s=45.0, jitter_ratio=0.15):
    process(t)

# Disable jitter if you need a fixed cadence
async for t in xc.stream(interval_s=30.0, jitter_ratio=0.0):
    process(t)

Fetch modes

Both fetch_tweets() and stream() accept a mode parameter that controls which tweets are returned:

Mode Behaviour
"new_only" (default) Only returns tweets newer than the last-seen cursor. The cursor advances so the same tweet is never emitted twice.
"all" Returns every tweet in each response. Nothing is filtered. Useful when your own store (e.g. a SQLite database) handles deduplication.
"with_updates" Returns new tweets and re-emits previously seen tweets whenever their metrics change (likes, retweets, views). Re-emitted tweets have is_update=True.
# Hand all deduplication to your own store
async for t in xc.stream(mode="all"):
    upsert_to_db(t)

# Only new tweets, cursor persisted across restarts
async with XTimelineClient(
    "curl.txt", persist_last_id_path="state/last_id.txt"
) as xc:
    async for t in xc.stream(mode="new_only"):
        process(t)

# New tweets + engagement updates
async for t in xc.stream(mode="with_updates"):
    if t.is_update:
        update_metrics_in_db(t)
    else:
        insert_new_tweet(t)

X gives every edit of a post a new id, so an edited post arrives as a new tweet (is_update=False). Check is_edit to replace the earlier version instead of storing it twice:

async for t in xc.stream(mode="with_updates"):
    if t.is_edit:
        replace_stored_version(t, version_ids=t.edit_tweet_ids)

Tweet fields

Each Tweet object contains:

Field Type Description
id int Tweet ID
text str Full text, HTML entities unescaped, t.co links expanded, long-form tweets supported
user_name str Display name
user_screen_name str @handle (without @)
user_img str Profile image URL
url str Canonical tweet URL
created_at str Post time in ISO 8601 format (2026-04-01T19:15:49Z)
likes int Like count
retweets int Retweet count
replies int Reply count
views int View count
media list[MediaItem] Attached photos/videos
tickers list[str] Uppercased $TICKER symbols
hashtags list[str] Uppercased hashtags
title str Human-readable summary, e.g. "TraderSZ retweeted Jelle"
is_update bool True if this tweet was seen in a previous fetch this session
edit_tweet_ids list[int] Ids of every version of an edited post, oldest first; empty if never edited
is_edit bool True if this tweet is an edited version of an earlier post (edit_tweet_ids[0] is the original)

Citation ✍️

If you use this project in your research, please cite as follows:

@misc{project_name,
  author  = {Stephan Akkerman},
  title   = {X-Timeline Scraper},
  year    = {2025},
  publisher = {GitHub},
  journal = {GitHub repository},
  howpublished = {\url{https://github.com/StephanAkkerman/x-timeline-scraper}}
}

Contributing 🛠

Contributions are welcome! If you have a feature request, bug report, or proposal for code refactoring, please feel free to open an issue on GitHub. We appreciate your help in improving this project.
https://github.com/StephanAkkerman/x-timeline-scraper/graphs/contributors

License 📜

This project is licensed under the MIT License. See the LICENSE file for details.

Metadata

Release files for xtimeline 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for xtimeline 0.3.0
File Size Uploaded
xtimeline-0.3.0.tar.gz 26.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for xtimeline 0.3.0
File Interpreter ABI Platform
xtimeline-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 43.6 kB

Release files / xtimeline-0.3.0.tar.gz

Download URL xtimeline-0.3.0.tar.gz
Size 26.3 kB
Tags Source
SHA-256 checksum
How to use checksums
83fc702bd200a45f49ced6a2a0913c127474267131ec0406f4024c2a109a4857
BLAKE2b-256 checksum
How to use checksums
3316dc019df56e342cf0962e305366bb0022f4514ed9ba623dc8e1a8e15019d6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.

Transparency log

Release files / xtimeline-0.3.0-py3-none-any.whl

Download URL xtimeline-0.3.0-py3-none-any.whl
Size 17.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5b40550d97c5eb05213e8a3f95b9b298079fc6ea1f86bdace27b6729263dd3d1
BLAKE2b-256 checksum
How to use checksums
87e49078df74b6817544e97013de1feb8f1c43cec07e4d1a4229da940e4d5dbc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page