@cm-growth-hacking/twitter-client
v0.2.0
Published
Lightweight Twitter/X GraphQL client and CLI
Maintainers
Readme
@thaddeus/twitter-client
Lightweight Twitter/X GraphQL client and CLI tool.
Quick Start
# Install
bun install
# Set credentials (get from browser DevTools → Application → Cookies)
export TWITTER_AUTH_TOKEN="your_auth_token"
export TWITTER_CT0="your_ct0_token"
# Search tweets
bun run src/cli.ts search "bitcoin"
# Post tweet
bun run src/cli.ts tweet "Hello World!"Features
- 🚀 Zero dependencies (except for CLI colors)
- 📝 Full TypeScript support
- 🔐 Cookie-based authentication
- 🎯 GraphQL API integration
- 💻 CLI tool included
- ⚡ Bun-optimized
Installation
npm install @thaddeus/twitter-clientBoth npm and bun work for installation.
Or globally for the CLI:
npm install -g @thaddeus/twitter-clientAuthentication
This client uses Twitter's cookie-based authentication (same as the web app). You'll need two values from your browser:
- auth_token - From cookie
auth_token - ct0 - From cookie
ct0
Getting Credentials
- Open Twitter/X in your browser
- Open Developer Tools (F12)
- Go to Application > Storage > Cookies
- Copy the values for
auth_tokenandct0
Setting Up Environment
Create a .env file:
TWITTER_AUTH_TOKEN=your_auth_token_here
TWITTER_CT0=your_ct0_hereKnown Limitations
- Tweet Posting Error 226: New or low-activity accounts may get "looks automated" error. Try posting from web interface first to warm up the account.
- Rate Limiting: Not yet implemented - Twitter may temporarily block rapid requests.
- Query ID Rotation: Query IDs rotate frequently (daily/weekly). Use
twitter update-query-ids --freshif commands fail.
Query ID Management
Twitter rotates GraphQL query IDs frequently. This client handles this automatically:
Auto-Refresh (Recommended):
- On 404 errors, the client automatically refreshes query IDs and retries
- No manual intervention needed
- Cache updated to
~/.config/twitter-client/query-ids.json(24h TTL)
Manual Refresh:
twitter update-query-ids # Update if cache is stale
twitter update-query-ids --fresh # Force refresh regardless of cache ageHow It Works:
- Client fetches Twitter's web client JavaScript bundle
- Extracts current query IDs using regex patterns
- Caches IDs locally with 24-hour TTL
- Falls back to baked-in IDs if scraping fails
Troubleshooting:
- If commands fail with "persisted query not found": Run
twitter update-query-ids --fresh - Check cache freshness:
cat ~/.config/twitter-client/query-ids.json - Clear cache:
rm ~/.config/twitter-client/query-ids.json
Commands
whoami
Shows your authenticated Twitter account information.
twitter whoamiExample output:
Logged in as: @username (Display Name)
User ID: 1234567890
Followers: 1,234
Following: 567Note: The whoami command uses Twitter's GraphQL API. If you encounter authentication errors, verify your environment variables are set correctly:
echo $TWITTER_AUTH_TOKEN
echo $TWITTER_CT0CLI Usage
Once installed globally, the twitter command is available:
# Show current user info
twitter whoami
# Search for tweets
twitter search "typescript"
# Post a tweet
twitter tweet "Hello, world!"
# Get a tweet by ID or URL
twitter get 1234567890
twitter get https://x.com/user/status/1234567890
# Get tweets from a user
twitter user username
# Get news timeline
twitter news
# Get mentions
twitter mentionsLibrary Usage
import { TwitterClient } from '@thaddeus/twitter-client';
const client = new TwitterClient({
authToken: process.env.TWITTER_AUTH_TOKEN!,
ct0: process.env.TWITTER_CT0!,
});
// Get current user info
const result = await client.whoami();
if (result.success) {
console.log(`@${result.user.username}`);
}
// Search for tweets
const searchResult = await client.search('typescript');
if (searchResult.success) {
searchResult.tweets.forEach(tweet => {
console.log(`@${tweet.author.username}: ${tweet.text}`);
});
}
// Post a tweet
const postResult = await client.tweet('Hello from the API!');
if (postResult.success) {
console.log(`Tweet ID: ${postResult.tweetId}`);
}
// Get a tweet
const tweetResult = await client.getTweet('1234567890');
if (tweetResult.success) {
console.log(tweetResult.tweet.text);
}
// Get user's tweets
const userResult = await client.getUserTweets('username');
if (userResult.success) {
userResult.tweets.forEach(tweet => {
console.log(tweet.text);
});
}
// Reply to a tweet
const replyResult = await client.reply('1234567890', 'This is a reply');
// Like a tweet
const likeResult = await client.likeTweet('1234567890');
// Unlike a tweet
const unlikeResult = await client.unlikeTweet('1234567890');
// Get news timeline
const newsResult = await client.getNews();
if (newsResult.success) {
newsResult.items.forEach(item => {
console.log(item.headline);
});
}
// Get mentions
const mentionsResult = await client.getMentions();
if (mentionsResult.success) {
mentionsResult.tweets.forEach(tweet => {
console.log(`@${tweet.author.username}: ${tweet.text}`);
});
}API Reference
TwitterClient
Constructor
new TwitterClient(options: {
authToken: string;
ct0: string;
timeout?: number;
})Methods
whoami(): Promise<UserResult>
Verify authentication and get current user info.
search(query: string, count?: number): Promise<SearchResult>
Search for tweets. Count must be between 1-200 (default: 20).
tweet(text: string): Promise<PostResult>
Post a new tweet.
getTweet(tweetIdOrUrl: string): Promise<TweetResult>
Get a single tweet by ID or URL.
getUserTweets(username: string, count?: number): Promise<TweetsResult>
Get recent tweets from a user.
reply(tweetId: string, text: string): Promise<PostResult>
Reply to a tweet.
likeTweet(tweetId: string): Promise<PostResult>
Like a tweet.
unlikeTweet(tweetId: string): Promise<PostResult>
Unlike a tweet.
getNews(count?: number): Promise<NewsResult>
Get news timeline (For You timeline). Count must be between 1-200 (default: 20).
getMentions(count?: number): Promise<TweetsResult>
Get mentions timeline. Count must be between 1-200 (default: 20).
Types
Tweet
interface Tweet {
id: string;
text: string;
author: User;
createdAt: string;
likeCount: number;
retweetCount: number;
replyCount: number;
quoteCount: number;
viewCount: number;
bookmarkCount: number;
media?: MediaItem[];
isQuote?: boolean;
quotedTweet?: Tweet;
isRetweet?: boolean;
retweetedTweet?: Tweet;
inReplyTo?: string;
conversationId?: string;
}User
interface User {
id: string;
username: string;
name: string;
description?: string;
followersCount?: number;
followingCount?: number;
isBlueVerified?: boolean;
profileImageUrl?: string;
createdAt?: string;
}Result<T>
All methods return a Result object:
interface Result<T> {
success: true;
data: T;
} | {
success: false;
error: string;
code: ErrorCode;
}Error Codes
AUTH_FAILED- Authentication credentials are invalid or expiredNETWORK_ERROR- Network request failedRATE_LIMITED- Rate limit exceededINVALID_INPUT- Invalid input parametersNOT_FOUND- Resource not foundSERVER_ERROR- Twitter server errorUNKNOWN_ERROR- Unknown error occurred
Development
# Install dependencies
bun install
# Run tests
bun test
# Run tests with live API calls
TWITTER_LIVE=1 bun test tests/live/
# Build
bun run build
# Run CLI directly
bun run devLicense
MIT
Contributing
Contributions are welcome! Please open an issue or submit a pull request.
Disclaimer
This project is not affiliated with Twitter/X. Use at your own risk and make sure to comply with Twitter's Terms of Service.
