x-kit: a pure-Python client for the X.com web endpoints
Pure-Python protocol tools and research notes for X.com, with VibeLoft Twitter account datasets
At a glance
- What is it?
- x-kit is a set of pure-Python scripts that speak the X.com web protocol directly, reading profiles, timelines, search results and tweet details, and writing tweets, retweets and quotes, with credentials taken from your own logged in browser session. It suits researchers and analysts who need reproducible collection rather than a hosted API, and it comes with explicit warnings about account level risk controls.
- Who is it for?
- Adopt x-kit if you need reproducible collection from the X.com web client, if you already have an authenticated session to take tokens from, and if you are prepared to treat write operations as risky. Do not adopt it as a way to operate at scale against accounts you do not own, and do not assume the token injection makes traffic indistinguishable from a human browser.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A protocol client written in Python, not a wrapper around an API
x-kit is described as pure-Python protocol tools and research notes for the X.com web client. The word protocol is the important one. There is no official API call here, no developer portal and no API key. The scripts speak the same internal endpoints the X.com web page uses, which means the capability set is whatever the web client exposes and the fragility is whatever the web client decides to change.
The repository also documents its own history. The README says the project now uses the Python protocol implementation as the source of truth, and that the previous Bun and TypeScript automation has been removed, with selected full-user tweet exports preserved under data/user_tweets/. So this is a rewrite that chose one language, and the artefacts of the old implementation survive as datasets rather than as code.
The audience is narrow and the README makes it clear. This is a research repository: ANALYSIS.md records the reverse-engineering findings and the current GraphQL operation IDs, and the topics list the project under crawler, protocol, twitter and x-com. The tooling is a set of small single-purpose scripts, one per operation, which is a shape that suits someone running a command at a time and reading the output rather than someone embedding a library.
The maintenance record is current. The last push was on 2026-10-20, the repository is not archived, no GitHub releases are published, and the package metadata gives the version as 0.1.0 with Python 3.12 or newer required. The licence is MIT.
Setup is uv sync plus two values from your own session
Installation follows the usual uv workflow, and the dependency set is small enough to read at a glance. The project metadata lists Beautiful Soup, httpx, requests and xclienttransaction, and requires Python 3.12 or newer.
uv sync
cp config/settings.example.json config/settings.jsonYou then fill in two fields in config/settings.json, auth.auth_token and auth.ct0. The README is explicit about where they come from: both values come from an authenticated browser session on x.com, and config/settings.json is ignored by Git.
Credentials can also be passed at runtime, which is what you want in a script or a CI job that should not write a token to disk.
uv run user.py HiTw93 --auth-token "$AUTH_TOKEN" --ct0 "$CT0"The script names are the interface. user.py resolves a profile, read.py fetches a tweet detail, user_tweets.py collects a timeline with a page count and an output file, search.py walks search results and can work in date windows for deeper history, tweet.py creates a tweet with optional media, and repost.py handles retweets and quote tweets.
uv run user_tweets.py HiTw93 --pages 3 -o tweets.json
uv run search.py --from HiTw93 --all -o hitw93_full.json
uv run read.py https://x.com/i/status/2062521510938779729The last line matters for permissions. The repository includes a Notes section that says write operations can trigger account level limits and risk controls, and advises deliberate delays and avoiding automation bursts. There is also a line telling you not to commit cookies, captured private payloads, or personal datasets, which is a sensible rule for a tool whose whole input is a session cookie.
Four GraphQL operations cover the read side
The capability list in the README maps directly onto GraphQL operations, which is the clearest statement of what the tool actually reaches.
Reading a single tweet is TweetDetail. Resolving a profile is UserByScreenName. Collecting a user timeline is UserTweets. Collecting search results is SearchTimeline, and that one has a notable extra, date window pagination for deeper history, which is the mechanism behind the --all flag on search.py. Without it, a search returns whatever the site's own paging exposes, and the date window trick is how you walk further back than the timeline.
Two of those deserve a note on scope. UserTweets gives you the recent timeline of one account, and the search path with date windows gives you a deeper, less complete history of the same person. The README treats these as different tools, and the difference in coverage is real, so a script that needs a full archive has to use search and accept that the result is a search result rather than a clean timeline.
The write side is smaller. tweet.py creates a tweet with optional media upload, and repost.py can retweet, quote tweet, or copy public tweet text and media into a new tweet. The copy operation is worth understanding, because it is the one that turns a public tweet into a new post rather than a like or a share.
Everything above rides on operation IDs that the README treats as deployment artifacts. It says query IDs and feature flags are deployment artifacts, and that you should refresh them if X.com changes its web bundle. That single sentence is the most important operational fact in the repository, and it belongs in your plan before you rely on any of it.
The transaction id header, and why the thin wrapper was dropped
One capability deserves a close reading, because the project explains it in unusually blunt terms. The README lists automatic injection of x-client-transaction-id for /i/api/ requests, and the dependency comment in pyproject.toml explains why the obvious package was abandoned.
The comment says the maintained one is xclienttransaction, and that a thin wrapper around it was not released since 2025-04-30. It continues that both install the same x_client_transaction module, so the wrapper only ever pinned the real package looser. It adds that version 1.0.2 of the wrapper stopped being able to find ondemand.s.js on the current x.com homepage, and that every request then fell back to sending no x-client-transaction-id, which the comment describes as the header X uses to spot automation.
That is a candid admission with a practical consequence. The header is part of how the platform identifies automated traffic, and this project deliberately supplies it. That makes the tooling more faithful to a real browser session, and it also means the behaviour of the tool is tied to a moving target: a script that used to work may start working differently, or appear differently to the platform, the moment the site's bundle changes.
The dependency pin reflects that thinking, requiring xclienttransaction at 1.0.3 or newer, and the comment exists in the metadata to stop a future maintainer from reintroducing the looser pin. For a user, the takeaway is that the version of this dependency is not an incidental detail, and that the README's instruction to refresh operation IDs when the bundle changes applies to this piece of the stack too.
Rate limits pause the sequential collection instead of failing it
The repository carries a collection pipeline for a specific dataset, and the design of that pipeline is more instructive than the dataset itself.
The pieces are separate scripts with separate jobs. collect_vibeloft_twitter_accounts.py collects the public VibeLoft profiles that expose Twitter and X links, and collect_twitter_profile_stats.py collects the post and follower counts for those accounts. A sequential task, scripts/collect_vibeloft_twitter_sequence.py, walks every account one after another, and a status script, scripts/twitter_collection_status.py, reports the latest collection state per user or for the whole set.
The state files make the design legible. data/vibeloft_twitter_accounts.json records the public profiles, data/vibeloft_twitter_x_stats.json records the post and follower counts, and data/user_tweets/latest_collection_status.json records, for each collected user, the latest collection time, the newest tweet time, the oldest tweet time, the tweet count, the output file, and the failure or pause status. A separate sequence_state.json records the cursor.
And the cursor is the point. The README says that if X returns a rate limit, the sequence pauses and resumes from the same user after the reset window. So a rate limit is not an error to be retried blindly, it is a state to be persisted and resumed from. The per-user exports land in data/user_tweets/vibeloft/.
That is the part of x-kit worth borrowing even if you never touch the VibeLoft data, because it is the difference between a scraper that loses an afternoon's work to a rate limit and one that carries on.
Where x-kit is the wrong tool
Three objections are serious enough to state plainly.
The first is durability. This project talks to internal web endpoints whose names and payloads are deployment artifacts. The README says to refresh the operation IDs when X.com changes its web bundle, which is an admission that breakage is expected rather than exceptional. If your job depends on this data arriving on a schedule, you need to treat breakage as a routine event and detect it, and the tool gives you a status file to help with that. If your job cannot tolerate a gap, use a supported interface instead.
The second is the write side. The capability list includes creating tweets, retweeting, quoting and copying public tweet text and media into new posts, and the README warns that write operations can trigger account level limits and risk controls. Whatever the automation is for, the account you point it at is the account that gets restricted, and the restriction lands on a human's account rather than on the script. The read only commands are the safe part.
The third is the legal and terms question, which this article does not answer. Reading public data, storing it and republishing it are different acts with different consequences, and the dataset directories in this repository contain exported timelines and follower statistics for real accounts. The README's instruction not to commit cookies, captured private payloads or personal datasets is a warning, not a licence.
A fourth, smaller point: the scripts are one-per-operation rather than a library. There is no client object to hold, no session management, no retry policy, no rate limit handling outside the sequential collector. If you want to build something on top, you are writing that plumbing yourself, and this repository gives you a reference implementation of the requests rather than a component to depend on.
Editorial conclusion
Adopt x-kit if you need reproducible collection from the X.com web client, if you already have an authenticated session to take tokens from, and if you are prepared to treat write operations as risky. Do not adopt it as a way to operate at scale against accounts you do not own, and do not assume the token injection makes traffic indistinguishable from a human browser. Verify first that the query IDs in ANALYSIS.md still match the live X.com bundle, because they are deployment artifacts that break when the site ships a new web build, and start with the read only commands before you use tweet.py or repost.py on an account that matters.
Frequently asked questions
What is x-kit and what can it do?
x-kit is a set of pure-Python protocol tools for the X.com web client. It reads tweet details through TweetDetail, resolves profiles through UserByScreenName, collects timelines through UserTweets, gathers search results through SearchTimeline with date window pagination, and can create, retweet and quote tweets.
How do I set up x-kit and provide credentials?
Run uv sync, copy config/settings.example.json to config/settings.json, and fill in auth.auth_token and auth.ct0, both of which come from an authenticated browser session on x.com. You can also pass them at runtime with flags such as --auth-token and --ct0, and config/settings.json is ignored by Git.
Why does x-kit depend on xclienttransaction?
The dependency comment in pyproject.toml explains that an older thin wrapper stopped being able to find ondemand.s.js on the current x.com homepage, so requests fell back to sending no x-client-transaction-id, which is the header X uses to spot automation. The maintained package is required at 1.0.3 or newer.
How does x-kit handle X.com rate limits during collection?
The sequential collection task pauses when X returns a rate limit and resumes from the same user after the reset window, with the cursor kept in data/user_tweets/sequence_state.json. Per-user status, including the latest collection time and failure or pause status, is recorded in data/user_tweets/latest_collection_status.json.
What breaks when X.com changes its web bundle?
The README says query IDs and feature flags are deployment artifacts, and that they should be refreshed if X.com changes its web bundle. The current GraphQL operation IDs are recorded in ANALYSIS.md together with the reverse-engineering findings.
Can x-kit post to X.com?
Yes, tweet.py creates a tweet with optional media upload, and repost.py can retweet, quote tweet, or copy public tweet text and media into a new tweet. The README warns that write operations can trigger account level limits and risk controls and advises deliberate delays.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/xiaoxiunique-x-kit)Was this useful?