xcompare.py is a lightweight Python 3 CLI that imitates the public Twitter/X web client. It reuses the public web bearer plus a temporary guest token (or, optionally, your browser cookies) to download followers for two accounts and report the overlap—no developer portal keys required.
This tool is developed and maintained by OffSeq — learn more at offseq.com, x.com/offseq, LinkedIn, or infosec.exchange/@offseq.
- Python 3.9+
- Network access to
https://x.com - (Optional) Browser cookies if you need to access protected accounts. Copy the entire
Cookieheader (withauth_tokenandct0) from your browser’s dev tools and pass it via--cookieor--cookie-file.
python3 xcompare.py <username_a> <username_b> [options]Key options:
| Flag | Description |
|---|---|
--cookie "auth_token=...; ct0=..." |
Reuse a logged-in browser session if guest access isn’t enough. |
--cookie-file path |
Read the cookie header from a file instead of the CLI. |
--max-followers N |
Limit how many followers to fetch per account (default 2000). |
--delay SECONDS |
Pause between paginated requests to avoid rate limits (default 1). |
--web-bearer TOKEN |
Override the public web bearer token (defaults to the value used by x.com); you can also set X_WEB_BEARER_TOKEN. |
--json |
Emit raw JSON for automation; pair with --pretty for indentation. |
--quiet |
Hide progress messages printed to stderr. |
Example:
python3 xcompare.py nasa spacex --max-followers 4000 --json --prettyOutput example:
Resolved @nasa -> 1..
Resolved @spacex -> 2..
Fetched 200 follower(s) so far for user 1.. (more available)
Fetched 400 follower(s) so far for user 1.. (more available)
Fetched 600 follower(s) so far for user 1.. (more available)
Fetched 800 follower(s) so far for user 1.. (more available)
Fetched 1000 follower(s) so far for user 1.. (more available)
Fetched 1200 follower(s) so far for user 1.. (more available)
Fetched 1400 follower(s) so far for user 1.. (more available)
Fetched 1600 follower(s) so far for user 1.. (more available)
Fetched 1800 follower(s) so far for user 1.. (more available)
Fetched 2000 follower(s) so far for user 1.. (more available)
Fetched 200 follower(s) so far for user 2.. (more available)
Fetched 400 follower(s) so far for user 2.. (more available)
Fetched 600 follower(s) so far for user 2.. (more available)
Fetched 800 follower(s) so far for user 2.. (more available)
Fetched 1000 follower(s) so far for user 2.. (more available)
Fetched 1200 follower(s) so far for user 2.. (more available)
Fetched 1400 follower(s) so far for user 2.. (more available)
Fetched 1600 follower(s) so far for user 2.. (more available)
Fetched 1800 follower(s) so far for user 2.. (more available)
Fetched 2000 follower(s) so far for user 2.. (more available)
Found 4 overlapping follower(s):
• @OffSeq (Offensive Sequence) [followers:17583, following:0]
• @xxx0 (example0) [followers:187, following:1115]
• @xxx1 (example1) [followers:1596, following:1123]
• @xxx2 (example2) [followers:11, following:386]
The script prints the overlap or exits with an error if X blocks the request (private account, 2FA-required session, rate limits, etc.). Start with a small --max-followers value to confirm the guest/cookie session works, then scale up gradually. Increase --delay if you begin to see HTTP 429 responses.
Seeing
Guest activation failed (403 Forbidden)? X occasionally disables anonymous guest tokens. Open Developer Tools while logged intohttps://x.com, grab theCookieheader from any request (it must includeauth_tokenandct0), and supply it via--cookieor save it to a file referenced by--cookie-file.
You can either paste the literal Cookie header (recommended) or save the JSON blob Firefox/Chrome provide when you choose “Copy request headers”; xcompare.py reads that JSON and extracts the cookie value automatically.
If X rotates the public bearer in the future, copy the authorization: Bearer … header from DevTools and pass just the token via --web-bearer (or set X_WEB_BEARER_TOKEN) so the CLI stays in sync.
https://offseq.com/ https://radar.offseq.com/ https://guard.offseq.com/