clawuth
v0.1.1
Published
X/Twitter client using browser session tokens — multi-account CLI + Spaces host/listener
Maintainers
Readme
clawuth
A lightweight X/Twitter client that uses your real browser session tokens to call X's internal GraphQL API. No scraping, no Playwright, no official API keys — just direct HTTP calls.
clawuth tweet "Hello from clawuth!"What It Is
clawuth makes it easy to interact with X programmatically using the same requests your browser makes. You extract two cookie values from your browser (takes 30 seconds), and clawuth handles all the auth headers, GraphQL wiring, and response parsing.
No dependencies. Node 18+ built-ins only: fetch, fs, path, readline.
60-Second Quickstart
1. Install
git clone https://github.com/yourname/clawuth
cd clawuth
npm link # makes the `clawuth` command available globally2. Run setup
clawuth setupThe wizard will:
- Tell you to open x.com in your browser
- Show you a DevTools snippet to copy your session tokens
- Ask for an account name and the pasted JSON
- Save everything to
~/.clawuth/accounts.json
3. Tweet!
clawuth tweet "Hello from clawuth! 🚀"CLI Reference
clawuth <command> [args]| Command | Description |
|---|---|
| setup | Interactive account setup wizard |
| accounts list | List all configured accounts |
| accounts add <name> | Add a new account by name |
| accounts default <name> | Set the default account |
| tweet <text> | Post a tweet |
| tweet <text> --reply <id> | Reply to a tweet |
| like <tweetId> | Like a tweet |
| timeline | Show your home timeline (last 10 tweets) |
| search <query> | Search for tweets |
| whoami | Show the current account info |
Programmatic API Reference
Setup
import { ClawuthClient } from 'clawuth';
const client = new ClawuthClient(); // uses default account
const client = new ClawuthClient('myacct'); // uses named accountTweets
// Post a tweet
const tweet = await client.tweet('Hello world!');
// Reply to a tweet
await client.reply('1234567890', 'Great point!');
// Post with options
await client.tweet('Check this out!', {
replyToId: '1234567890', // reply to this tweet
quoteUrl: 'https://x.com/user/status/123', // quote tweet URL
mediaIds: ['media_id_1'], // pre-uploaded media IDs
});
// Delete a tweet
await client.deleteTweet('1234567890');
// Get a single tweet
const tweet = await client.getTweet('1234567890');Interactions
await client.like('1234567890');
await client.unlike('1234567890');
await client.retweet('1234567890');
await client.unretweet('1234567890');Timeline
// Home timeline (last 20 tweets)
const { tweets, nextCursor } = await client.timeline({ count: 20 });
// Load more using cursor
const { tweets: more } = await client.timeline({ count: 20, cursor: nextCursor });
// Notifications / mentions
const data = await client.notifications({ count: 20 });
const data = await client.mentions({ count: 20 });Search
const { tweets, nextCursor } = await client.search('AI agents', {
count: 20,
filter: 'Latest', // 'Latest' | 'Top' | 'People' | 'Photos' | 'Videos'
});Users
// By screen name (with or without @)
const user = await client.getUser('@myaccount');
const user = await client.getUser('myaccount');
// By numeric ID
const user = await client.getUser('12345678');
// Follow / unfollow
await client.follow('12345678');
await client.unfollow('12345678');Auth helpers
import { addAccount, listAccounts, setDefault } from 'clawuth';
addAccount('myacct', authToken, ct0, 'myusername');
setDefault('myacct');
const accounts = listAccounts();Multiple Accounts
You can configure as many accounts as you like:
clawuth accounts add personal
clawuth accounts add work
clawuth accounts list
clawuth accounts default workOr programmatically:
import { addAccount } from 'clawuth';
addAccount('personal', 'auth_token_1', 'ct0_1', 'myhandle');
addAccount('work', 'auth_token_2', 'ct0_2', 'workhandle');
const client = new ClawuthClient('work');All accounts are stored in ~/.clawuth/accounts.json.
Token Extraction
Run clawuth setup and follow the prompts — it shows you exactly what to paste in DevTools.
For manual extraction, see scripts/extract-tokens.js for detailed instructions, including the manual cookie extraction method.
⚠️ Token Expiry
Tokens expire when you log out of x.com. If you see a 401 Auth error, your tokens have expired. Re-run clawuth setup (or clawuth accounts add <name>) to refresh them.
To avoid expiry: stay logged in to x.com in your browser. Tokens are session-based and tied to your browser login.
Config File
~/.clawuth/accounts.json looks like:
{
"__default": "myaccount",
"myaccount": {
"name": "myaccount",
"username": "myaccount",
"authToken": "...",
"ct0": "...",
"addedAt": "2024-01-01T00:00:00.000Z"
}
}OpenClaw Channel Plugin
clawuth ships a companion OpenClaw channel plugin that makes X a proper two-way messaging channel — @mentions and DMs arrive in any OpenClaw surface (Telegram, webchat, etc.), and replies post back to X automatically.
Install
Copy (or symlink) the plugin into your OpenClaw extensions directory:
cp -r plugins/openclaw-x ~/.openclaw/extensions/xOr point OpenClaw at it via plugins.load.paths in your config.
Configure
Add to your OpenClaw config (~/.openclaw/config.json5):
{
channels: {
x: {
enabled: true,
accounts: {
default: {
authToken: "your_auth_token", // from DevTools → Application → Cookies → https://x.com
ct0: "your_ct0", // same place
username: "yourusername", // without @
watchMentions: true,
watchDMs: true,
pollIntervalMs: 60000 // check every 60s
}
}
}
}
}Activate
openclaw gateway restartX is now a channel. @mentions and DMs flow in; replies flow out.
X Spaces
Hosting a Space (AI host with voice)
clawuth can host a live X Space with AI-generated speech. Two TTS backends are supported:
Option A — Local Voice Lab (recommended, offline)
Runs on your machine using Kokoro TTS. No API key needed.
# Start the Voice Lab server (one-time setup)
cd ~/voice-lab && python server.py
# Start a Space
clawuth space start "AI and the Future of Open Source"Available voices: af_nicole (default), af_sarah, af_bella, bm_george, bm_lewis, and more.
VOICE_LAB_VOICE=af_sarah clawuth space start "My Topic"Option B — ElevenLabs (cloud, works anywhere)
export ELEVENLABS_API_KEY=your_key_here
clawuth space start "My Topic"Available voices: Sarah (default), Liam, Charlotte, Brian, Jessica.
ELEVENLABS_VOICE_ID=TX3LPaxmHKxFdv7VOQHJ clawuth space start "My Topic"Backend selection
clawuth auto-detects which backend to use:
- Voice Lab — if server is running at
localhost:8002 - ElevenLabs — if
ELEVENLABS_API_KEYis set - Error if neither is available
Force a specific backend:
TTS_BACKEND=elevenlabs clawuth space start "My Topic"
TTS_BACKEND=voicelab clawuth space start "My Topic"Also requires FFmpeg: brew install ffmpeg
Listening to a Space (keyword alerts)
Monitor any public Space for keywords. Transcribes live audio using Deepgram.
clawuth space listen https://x.com/i/spaces/XXXXX \
--keywords "openclaw,vibeclaw,agent" \
--transcript \
--alertOptions:
--keywords "a,b,c"— comma-separated keywords to watch for--transcript— print live transcript to stdout--alert— send OpenClaw notification on keyword match (default: on)--webhook <url>— POST to URL on keyword match--anon— join as anonymous listener (no account needed)--account <name>— use a specific account
# Show Space info without joining
clawuth space info https://x.com/i/spaces/XXXXXRequirements
- Node.js 22+ (built-in
fetch+WebSocket) - An active x.com account
- FFmpeg (for Spaces):
brew install ffmpeg - For TTS: Voice Lab (local) OR
ELEVENLABS_API_KEY(cloud) - For transcription: Deepgram API key (
DEEPGRAM_API_KEY) - No npm dependencies
License
MIT
