X Tweet Fetcher AI Agent

by ythx-101• 998•• Scanned•Claim this listing•Request removal
Social Mediaagent toolsai agentautomationno apiosint

Fetch X/Twitter tweets, replies, timelines, and articles without login or API keys — field tool for AI agents.

X Tweet Fetcher is an open-source ai agent by ythx-101, written mainly in Python, with 998 GitHub stars and the MIT license. Its code was last updated Oct 14, 2026.

<div align="center">

x-tweet-fetcher

Fetch X/Twitter tweets, replies, timelines, lists, and articles — no login, no API keys.

License: MIT Python 3.10+ GitHub stars

Three backends · Auto fallback · Unified JSON schema · Built for AI agents

Quick Start · Backends · Capabilities · When to use · FAQ · Python API · Self-hosted Nitter · Migrating from v1

</div>

x-tweet-fetcher (xtf) is a Python CLI and library that lets AI agents and developers fetch X/Twitter tweets, replies, timelines, search results, Lists and X Articles without logging in or using the X API — it routes between FxTwitter, Nitter and a browser driver with automatic fallback and returns one unified JSON schema.

中文简介

免登录、免 API key 抓取 X(推特)的推文、回复、时间线、搜索、Lists 和长文(X Articles)。适合给 AI agent(OpenClaw、Claude Code 等能跑命令行的 agent)当“读推特”的工具,无需 API,输出统一 JSON,并可存入本地 SQLite 推文库。单条推文零依赖;时间线/搜索需要 Nitter;Lists 可走 Nitter 或浏览器;X Article 需要浏览器。


😤 Problem

You: fetch that tweet / list / article for me
AI:  I can't access X/Twitter. Please copy-paste the content manually.

You: ...seriously?

X has no free API. Scraping gets you blocked. Browser automation is fragile in headless environments.

x-tweet-fetcher solves this with smart backend routing: FxTwitter for single tweets (zero deps), Nitter for timelines and search (direct HTTP), a browser driver for everything else — with automatic fallback between them.

🚀 Quick Start

git clone https://github.com/ythx-101/x-tweet-fetcher
cd x-tweet-fetcher && pip install .

# Or in one step (not published on PyPI):
pip install git+https://github.com/ythx-101/x-tweet-fetcher

# Single tweet — works instantly, zero configuration
xtf --url https://x.com/user/status/1234567890

# User timeline (needs a Nitter instance, see below)
export XTF_NITTER=http://127.0.0.1:8788
xtf --user elonmusk --limit 20

# Search
xtf --search "openclaw" --limit 10

# Human-readable output instead of JSON
xtf --user elonmusk --text-only

Prefer not to install? python3 scripts/fetch_tweet.py --url ... works straight from the clone (same flags).

🔀 Three Backends

BackendDepsSpeedCovers
fxtwitterNone (stdlib)⚡⚡Single tweets, user profiles
nitterA Nitter instance⚡Timeline, search, replies, mentions, Lists
browserCamofox or Playwright🐢Everything above + X Articles (also the Lists fallback)
auto (default)Best available⚡→🐢Nitter first, browser fallback
xtf --user elonmusk                    # auto (default)
xtf --user elonmusk --backend nitter   # direct HTTP only
xtf --list 1455045069516357634         # Lists: Nitter first, browser fallback

Browser driver defaults to Camofox (localhost:9377). Playwright users:

pip install ".[playwright]"            # from the clone
export XTF_BROWSER=playwright          # or: --browser-driver playwright

📊 Capabilities

FeatureFlagBackend
Single tweet (text, stats, media, quotes)--urlfxtwitter
Reply comments (threaded)--url --repliesnitter / browser
User timeline (paginated)--usernitter / browser
Search--searchnitter
User profile--user-infofxtwitter → nitter
X List tweets--listnitter / browser
X Article full text--articlebrowser
Mentions monitor (incremental, cron-friendly)--monitornitter / browser
Archive fetch results (dedupe, SQLite)--ledger <db>any
Search / stats the archive (offline)--ledger <db> --query/--statsoffline

Exit codes (cron-friendly): 0 success / no new mentions · 1 error / new mentions found · 2 monitor setup error.

Errors are machine-readable. Every failure carries error (human message) plus error_code — one of invalid_input, not_found, rate_limited, upstream_down, backend_unavailable, all_backends_failed — so agents can branch on it. all_backends_failed additionally includes per-backend error_causes.

🧭 When to use / Alternatives

ApproachLogin / keysGood forTrade-off
Official X APIDeveloper account + API keysProduction, write access, guaranteed termsAccount setup, paid access tiers
Account-based scrapersRequires X accounts / cookiesLarge-scale collectionAccount ban risk, credential handling
x-tweet-fetcherNone for single tweets; your own Nitter / browser for the restAI agents reading tweets on demand, small archivesDepends on FxTwitter / Nitter / page structure; read-only

Use it when…

  • an AI agent or script needs to read a tweet, thread, timeline or List on demand, without handling X credentials;
  • you want one JSON shape no matter which backend answered;
  • you want a small local archive of what you fetched (--ledger).

Don't use it when…

  • you need to post or do anything other than read — xtf is read-only;
  • you need contractual guarantees or official support for production workloads — use the official X API.

📚 推文库 (Ledger)

--ledger <db> turns xtf into a fetch + archive + query local tweet library: every timeline / search / list / replies / single-tweet fetch is archived into a SQLite DB, deduped by tweet_id (INSERT OR IGNORE, idempotent). Schema is compatible with the tweet-ledger (OpenClaw) tweets table, so the same DB can be read by both tools.

# Fetch + archive a timeline
xtf --user YuLin807 --limit 20 --ledger ~/tweets.db

# Search the archive (offline)
xtf --ledger ~/tweets.db --query "sop"

# Stats: totals, languages, media/urls, time ranges
xtf --ledger ~/tweets.db --stats

Behavior without --ledger is unchanged (3.0.0-compatible). Archiving never breaks a successful fetch — on failure the JSON envelope carries ledger_error instead. Single-tweet (fxtwitter) dicts lack tweet_id, so the CLI injects it from the URL; --replies results are archived with is_reply=1 and in_reply_to_status_id pointing at the parent tweet.

tweets table: tweet_id (PK) · created_at · full_text · lang · source_file · is_reply · in_reply_to_status_id · retweeted_status_id · quoted_status_id · urls_json · media_json · raw_json · imported_at

End-to-end integration test record: docs/e2e-integration.md.

🐍 Python API

from xtf import Router, NotFound, RateLimited

router = Router()                                  # backend="auto"
tweet   = router.fetch_tweet("user", "1234567890") # dict, v1-compatible shape
tweets  = router.fetch_timeline("user", limit=20)  # list[Tweet]
replies = router.fetch_replies("user", "1234567890")
results = router.search("openclaw", limit=10)

for tw in tweets:
    print(tw.author, tw.likes, tw.text)
    print(tw.to_dict())                            # JSON-ready

All backends normalize into one Tweet / Reply / Profile / Article schema — your downstream prompt only ever needs to describe one shape.

⚙️ Configuration

Everything is an environment variable (CLI flags override):

VariableDefaultMeaning
XTF_NITTERhttp://127.0.0.1:8788Comma-separated Nitter instances, tried in order with failover
XTF_BROWSERcamofoxBrowser driver: camofox or playwright
XTF_BROWSER_PORT9377Camofox HTTP port
XTF_LANGzhMessage language: zh or en
XTF_CACHE_DIR~/.x-tweet-fetcherMentions-monitor cache

NITTER_URL (the v1 name) is still honored as a fallback for XTF_NITTER.

🏗 Self-hosted Nitter

Public Nitter instances are unreliable and frequently dead. Self-hosting is strongly recommended for timeline/search/replies:

Running your own instance needs two things: a nitter.conf (copy the official nitter.example.conf and edit it) and a separately running Redis/Valkey. Follow the official guide, including the docker-compose option: https://github.com/zedeus/nitter#docker. The official single-container example is:

docker run -v $(pwd)/nitter.conf:/src/nitter.conf -d --network host zedeus/nitter:latest

Start Redis first, and set the port in nitter.conf to the one you want. Then point xtf at it:

export XTF_NITTER=http://127.0.0.1:<port>

Multiple instances failover automatically:

export XTF_NITTER=http://127.0.0.1:8788,https://your-backup-instance.example

If no instance is reachable, you get a clear error (error_code: "all_backends_failed", with each backend's reason — e.g. backend_unavailable — under error_causes) telling you exactly what to set. Never a silent empty result.

📁 Project Structure

src/xtf/
├── models.py        # Tweet / Reply / Profile / Article dataclasses
├── backends/
│   ├── fxtwitter.py # single tweets + profiles
│   ├── nitter.py    # direct HTTP, multi-instance failover
│   └── browser.py   # Camofox / Playwright snapshot fetching
├── parsers/         # pure functions, locked by fixture tests
├── router.py        # auto-fallback chain
├── monitor.py       # incremental mentions monitor
└── cli.py           # the `xtf` command
scripts/fetch_tweet.py   # v1-compatible entry point (thin shim)
tests/fixtures/          # captured page structures — regression protection

❓ FAQ

Do I need an X/Twitter API key or account? / 需要 API key 或登录吗? No. Single tweets go through FxTwitter with no setup. Full X Article text needs a browser that is already logged in to X; otherwise you get the title plus the public preview (is_partial: true).

Why does --user / --search fail with all_backends_failed? No Nitter instance was reachable. Set XTF_NITTER to a working instance and check error_causes in the output for each backend's reason.

Can I use public Nitter instances? Yes — XTF_NITTER accepts several comma-separated instances and fails over between them. Public instances are often unreliable, so self-hosting is recommended.

How do I use it from an AI agent (OpenClaw, Claude Code, others)? Have the agent run xtf ..., parse the JSON, and branch on error_code. The repo ships a SKILL.md describing the commands.

Can it fetch X Lists and X Articles? Lists: Nitter first, browser fallback. Articles: browser only (Camofox or Playwright).

How do I keep a local archive? / 怎么存档? Add --ledger <db> to any fetch; query it offline with --ledger <db> --query <term> or --stats.

Is it on PyPI? Not currently. Install from source: pip install git+https://github.com/ythx-101/x-tweet-fetcher.

Does it post or write to X? No, it is read-only.

🔄 Migrating from v1

python3 scripts/fetch_tweet.py still works with all v1 flags and exit codes, and JSON fields are unchanged for every mode except --search, whose per-tweet schema is now unified with --user (fields renamed, url/has_media/media_urls dropped). See MIGRATION.md for the full list, including where the analytics/China/Obsidian scripts went (spoiler: their own repos — this project is now purely about fetching tweets; the old world lives at the v1-legacy tag).

🧪 Development

pip install -e ".[dev]"
pytest          # all parsers locked by fixture tests
ruff check src tests

When Nitter or X change their page structure, capture a fresh snapshot into tests/fixtures/ — the failing test will show exactly which parser and field broke.

🙏 Acknowledgments

📜 License

MIT


<div align="center">

Three backends. Auto fallback. Built for AI agents.

GitHub · Issues · #22 Teahouse · Agent Waystation

</div>

X Tweet Fetcher alternatives

View more →

Similar ai agents in Social Media, ranked by GitHub stars. Compare licence, recent activity and scan status before you choose.

NameStarsLicenceLast updatedScan
X Tweet Fetcher (this page)
ythx-101
998MITOct 14, 2026Scanned, no flagged issues
Agent Reach
Panniantong
107kMITNov 1, 2026Scanned, no flagged issues
Autoclip
zhouxiaoka
9.9kMITNov 1, 2026Scanned, no flagged issues
ShortGPT
RayVentura
8.1kMITFeb 10, 2025Scanned, no flagged issues
Guizang Social Card Skill
op7418
7.9kAGPL-3.0Oct 30, 2026Scanned, no flagged issues
Tuios
Gaurav-Gosain
6.3kMITNov 1, 2026Scanned, no flagged issues