Read Twitter/X from your terminal. Zero API keys. Zero mutations. Pure signal.
Connects to your logged-in Chrome via CDP (Chrome DevTools Protocol). Intercepts Twitter's internal GraphQL responses directly. No API keys. No DOM scraping. No Selenium. No Playwright download. Just your Chrome + one command.
| Twitter API | Selenium/Playwright | headless-twitter | |
|---|---|---|---|
| API keys | Required ($100+/mo) | Not needed | Not needed |
| Browser download | N/A | ~400MB Chromium | Uses YOUR Chrome |
| Auth | OAuth dance | Cookie injection | Already logged in |
| Data source | REST/v2 endpoints | DOM scraping (fragile) | GraphQL intercept (stable) |
| Rate limits | Strict (100-500/15min) | Throttled by rendering | Twitter's own pagination |
| Mutations | Read + Write | Read + Write | Read-only enforced |
| Setup time | 30min+ (app registration) | 5min | 30 seconds |
npm install -g headless-twitterThat's it. No npx playwright install. No browser downloads.
# Your home timeline
headless-twitter twitter timeline '' 20
# Search tweets
headless-twitter twitter search "rust lang" 15
# Specific user
headless-twitter twitter user "@karpathy" 10
# Following feed
headless-twitter twitter following '' 20════════════════════════════════════════════════════════════════════════════════
📊 Twitter Feed
════════════════════════════════════════════════════════════════════════════════
[1] @kepano
I can't go back to the regular YouTube UI after this.
Obsidian Reader now makes the transcript interactive so you can scrub,
highlight, auto-scroll. It feels so nice.
📍 https://x.com/i/web/status/2042683393247449148
❤️ 10,771 | 🔄 723 | 💬 184
📅 Fri Apr 10 19:17:26 +0000 2026
────────────────────────────────────────────────────────────────────────────────
[2] @trq212
New in Claude Code: /ultraplan
Claude builds an implementation plan for you on the web...
📍 https://x.com/i/web/status/2042671370186973589
❤️ 9,658 | 🔄 632 | 💬 490
📅 Fri Apr 10 18:29:40 +0000 2026
────────────────────────────────────────────────────────────────────────────────
| Flag | Description | Default |
|---|---|---|
--lang LANG |
Filter by language (en, es, ja, hi, zh, ko...) |
all |
--cdp-url URL |
CDP endpoint | http://localhost:9222 |
--json |
Machine-readable JSON output | TUI |
--debug |
Show XHR endpoints and extraction details | off |
--help |
Show help | — |
# English only
headless-twitter twitter timeline '' 20 --lang en
# Japanese tweets about AI
headless-twitter twitter search "AI" 15 --lang ja
# All languages (no filter)
headless-twitter twitter timeline '' 20Pipe to jq, feed to scripts, or ingest into your app:
headless-twitter twitter timeline '' 20 --json | jq '.tweets[].text'{
"source": "twitter",
"mode": "timeline",
"query": "",
"count": 20,
"tweets": [
{
"id": "2042683393247449148",
"text": "I can't go back to the regular YouTube UI...",
"author": "kepano",
"lang": "en",
"likes": 10771,
"retweets": 723,
"replies": 184,
"time": "Fri Apr 10 19:17:26 +0000 2026",
"url": "https://x.com/i/web/status/2042683393247449148"
}
]
}┌─────────────┐ CDP ┌─────────────────┐ GraphQL ┌─────────────┐
│ Your Chrome │◄────────────►│ headless-twitter │◄─────────────│ Twitter/X │
│ (logged in) │ port 9222 │ (TypeScript) │ XHR intercept│ servers │
└─────────────┘ └─────────────────┘ └─────────────┘
Step by step:
- Connect — Attaches to your running Chrome via CDP (auto-launches if needed)
- Guard — Installs 3-layer read-only protection (see below)
- Navigate — Opens a new tab, goes to the target Twitter page
- Intercept — Captures GraphQL JSON responses as they stream in
- Scroll — Auto-scrolls to trigger more tweet loads
- Extract — Walks the GraphQL AST to pull out tweet data
- Filter — Applies language filter if specified
- Output — Renders TUI table or JSON
- Cleanup — Closes the tab, disconnects. Chrome stays running.
This tool is architecturally incapable of mutating your Twitter account:
Layer 1 — Network Block all POST/PUT/DELETE/PATCH requests via request interception
Layer 2 — DOM Freeze click/submit/input/change events via JS injection
Layer 3 — Code Zero page.click(), page.fill(), page.type() calls in source
No likes. No retweets. No follows. No DMs. No posts. By design, not by promise.
src/
├── types.ts Type definitions (Tweet, Config)
├── cli.ts Argument parsing, validation, help text
├── browser.ts CDP connection, Chrome auto-launch, profile management
├── extract.ts GraphQL response walker → Tweet[]
├── guards.ts 3-layer read-only enforcement + auto-scroll
├── format.ts TUI and JSON output formatters
└── index.ts Main orchestrator — wires everything together
~400 lines of TypeScript. Single dependency: puppeteer-core.
On first run, headless-twitter:
- Copies your Chrome profile to
~/.config/google-chrome-debug/ - Launches Chrome with
--remote-debugging-port=9222 - Connects via CDP, opens a tab, reads tweets, closes the tab
- Chrome stays running — subsequent runs connect in <1 second
Prerequisite: Chrome must be logged into Twitter/X before first run.
- AI agent feeds — Pipe
--jsonoutput into LLM context windows - Research — Collect tweets on a topic without API rate limits
- Monitoring — Watch accounts or search terms from cron
- Archival — Save timeline snapshots as JSON
- Content curation — Filter by language, pipe through
jq - CLI power users — Read Twitter without leaving the terminal
git clone https://github.com/om-ashish-soni/headless-twitter.git
cd headless-twitter
npm install
npm run build
node dist/index.js twitter timeline '' 10 --lang en- Node.js >= 18
- Chrome/Chromium installed and logged into Twitter/X
- Linux/macOS (Chrome CDP auto-launch uses
google-chromebinary)
Can it post tweets, like, or follow?
No. Architecturally impossible. All non-GET HTTP requests are blocked at the network level. DOM interactions are frozen. There are zero mutation calls in the source code.
Does it download a browser?
No. It uses puppeteer-core (not puppeteer), which connects to your existing Chrome. Zero browser downloads.
Will Twitter detect/ban this?
It uses your real Chrome with your real profile. To Twitter's servers, it looks like you scrolling your feed. No headless fingerprints. No automation signals.
How is this different from the Twitter API?
Twitter API requires registration, costs $100+/month for decent access, and has strict rate limits. This tool uses your existing login session and reads what you'd see in your browser — no API keys needed.
Does it work on Windows?
CDP connection works, but auto-launch currently targets Linux/macOS Chrome binary paths. You can manually launch Chrome with --remote-debugging-port=9222 and use --cdp-url to connect.
Can I use it with AI agents (Claude Code, OpenCode, etc.)?
Yes. Use --json output and pipe it into your agent's context. The tool ships with a SKILL.md for direct integration.
MIT — Om Ashish Soni