| name | twitter |
| description | This skill should be used when the user asks to "post a tweet", "read timeline", "check twitter", "like a tweet", "retweet", "search twitter", "manage twitter lists", "twitter auth", "get twitter user", "delete tweet", "trending topics", "what's trending", "bookmarks", "bookmark a tweet", "saved tweets", or mentions Twitter/X integration. Provides full Twitter API v2 access for posting, reading, engagement, bookmarks, and list management. |
| version | 1.3.0 |
Twitter/X API Integration
This skill provides full Twitter/X API integration through OAuth 2.0 PKCE authentication. Post tweets, read timelines, engage with content, search, view trends, and manage lists.
Script Location
The CLI script is located at:
${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts
Run commands using:
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts <command> [options]
First-Time Setup
Quick Start (Using Embedded Credentials)
Just run the auth command - no setup required:
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts auth
A browser will open for Twitter authentication. Authorize the app and you're ready to go.
Using Your Own Credentials (Optional)
If you prefer to use your own Twitter Developer credentials:
- Go to Twitter Developer Portal
- Create a new project and app
- In "User authentication settings":
- App type: "Web App, Automated App or Bot"
- App permissions: "Read and Write"
- Callback URI:
http://127.0.0.1:3000/callback (NOT localhost!)
- Website URL:
http://127.0.0.1:3000
- Copy Client ID and Client Secret
- Create
~/.config/twitter-skill/credentials.json:
{
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET"
}
Token Storage
Tokens are looked up in this order:
- Project-local:
.claude/twitter-skill.local.json (in current project directory)
- Global fallback:
~/.config/twitter-skill/tokens.json
This allows different projects to use different Twitter accounts, with a global default for projects without local tokens. Project-local tokens are automatically added to .gitignore.
Available Commands
Authentication
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts auth
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts auth --global
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts check
Response fields:
auth: Checks token validity and expiration
check: Returns { authenticated: boolean, user?: string, expiresAt?: string }
User Information
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts me
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts me --email
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts user elonmusk
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts user-id 44196397
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts users "44196397,12,178273"
Response fields for user objects:
id: User's unique ID
name: Display name
username: @handle (without the @)
created_at: Account creation date
description: Bio text
location: User-provided location
profile_image_url: Avatar URL
protected: Whether tweets are protected
verified: Whether account is verified
verified_type: Type of verification (e.g., "blue", "business", "government")
url: User's website URL
public_metrics: Object containing:
followers_count: Number of followers
following_count: Number following
tweet_count: Total tweets
listed_count: Times listed
Posting & Deleting Tweets
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts post "Hello from Claude Code!"
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts delete 1234567890
Important: Always confirm with the user before posting tweets.
Response fields:
post: Returns { id, text, url } - the url is the direct link to the posted tweet
delete: Returns { deleted: true } on success
Reading Tweets
Note on Long-Form Content (Articles/Note Tweets):
The skill automatically requests the note_tweet field. If a tweet contains long-form content (up to 25k chars), the full text will be returned in the note_tweet object within the response.
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts tweet 1234567890
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts tweets
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts timeline
Response fields for tweet objects:
id: Tweet's unique ID
text: Tweet content (up to 280 chars, or check note_tweet for long-form)
author_id: User ID of the author
created_at: When the tweet was posted
conversation_id: Thread ID (same as first tweet in thread)
source: App used to post (e.g., "Twitter Web App")
lang: Detected language code
public_metrics: Object containing:
retweet_count: Number of retweets
reply_count: Number of replies
like_count: Number of likes
quote_count: Number of quote tweets
bookmark_count: Number of bookmarks
impression_count: View count
entities: Object containing parsed URLs, mentions, hashtags
referenced_tweets: Array of { type, id } for retweets, quotes, replies
note_tweet: Object with { text, entities } for long-form content
Engagement
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts like 1234567890
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts unlike 1234567890
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts retweet 1234567890
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts unretweet 1234567890
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts retweeters 1234567890
Response fields:
like/unlike: Returns { liked: boolean }
retweet/unretweet: Returns { retweeted: boolean }
retweeters: Returns array of user objects (see User Information section)
Bookmarks
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts bookmarks
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts bookmark 1234567890
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts unbookmark 1234567890
Generate a navigable HTML archive of all bookmarks (with images, author profiles, search/sort)
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts bookmarks-archive reports/bookmarks.html
**Response fields:**
- `bookmarks`: Returns `{ tweets: [...], includes: { media: [...] } }` with tweet objects and media expansions
- `bookmark`: Returns `{ bookmarked: true }` on success
- `unbookmark`: Returns `{ bookmarked: false }` on success
- `bookmarks-archive`: Returns `{ path: string, tweets: number }` — the written file path and tweet count
### Search
```bash
# Search recent tweets (last 7 days)
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts search "claude ai"
Response: Returns array of tweet objects (see Reading Tweets section). Search queries support Twitter's search operators:
from:username - Tweets from a specific user
to:username - Replies to a specific user
#hashtag - Tweets with hashtag
"exact phrase" - Exact phrase match
-word - Exclude word
lang:en - Filter by language
Trends
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts trends
Note: This endpoint requires X Premium subscription for full data. Non-premium users may receive "Unknown" for category and post_count fields.
Response fields for trend objects:
trend_name: The trending topic or hashtag
category: Topic category (e.g., "Sports", "Entertainment", "Technology")
post_count: Approximate number of posts (e.g., "10K", "100K+")
trending_since: When the topic started trending
List Management
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts lists
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts list 1234567890
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts list-tweets 1234567890
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts list-members 1234567890
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts list-add <list-id> <user-id>
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts list-remove <list-id> <user-id>
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts list-create "My List" --description "Description" --private
pnpm tsx ${CLAUDE_PLUGIN_ROOT}/scripts/twitter.ts list-delete 1234567890
Response fields for list objects:
id: List's unique ID
name: List name
description: List description
private: Whether the list is private
owner_id: User ID of list owner
member_count: Number of members
follower_count: Number of followers
created_at: When the list was created
Response fields for operations:
list-add: Returns { is_member: true } on success
list-remove: Returns { is_member: false } on success
list-delete: Returns { deleted: true } on success
Response Format
All commands output JSON with a consistent structure:
{
"success": true,
"data": {
}
}
Error responses:
{
"success": false,
"error": "Error message here"
}
Rate Limit Information
The CLI outputs rate limit info to stderr after each request:
[rate-limit] /users/me: 75/75, resets in 15m
Status indicators:
- Normal:
X/Y - plenty of requests remaining
- Low:
X/Y (low) - less than 50% remaining
- Critical:
X/Y (CRITICAL) - less than 20% remaining
Common Workflows
Post a Tweet
- Confirm the tweet text with the user
- Run:
post "Tweet text"
- Return the tweet URL to the user
Check Notifications/Mentions
- Get the timeline:
timeline
- Filter for mentions or important accounts
- Summarize for the user
See What's Trending
- Get trends:
trends
- Present the top trending topics
- Search for tweets on interesting trends:
search "#trending_topic"
Manage Lists
- List existing lists:
lists
- Get members:
list-members <id>
- Add/remove members as needed
Review Bookmarks
- Get bookmarked tweets:
bookmarks
- Review saved tweets and summarize for the user
- Get full details on specific tweets:
tweet <id>
Research a Topic
- Search for tweets:
search "topic"
- Get specific tweets for more detail:
tweet <id>
- Get user info for context:
user <username>
Analyze Tweet Engagement
- Get the tweet:
tweet <id>
- Check public_metrics for engagement stats
- Get retweeters:
retweeters <id> to see who shared it
API Rate Limits
Twitter API v2 has rate limits. The most common:
- Tweets lookup: 300 requests per 15 minutes
- Post tweet: 200 tweets per 24 hours
- Like/Unlike: 50 per 24 hours
- Search: 180 requests per 15 minutes
- Trends: 75 requests per 15 minutes
The skill will return rate limit errors when exceeded.
Troubleshooting
"Something went wrong" during auth
- Ensure callback URL is
http://127.0.0.1:3000/callback (NOT localhost)
- Check that port 3000 is not in use
Token expires quickly
- The skill automatically refreshes tokens before expiry
- If issues persist, run
auth again
"Not authorized" errors
- Check that your app has the required permissions
- Run
auth to re-authenticate with updated scopes
Rate limit exceeded
- Wait for the rate limit window to reset (usually 15 minutes)
- Space out requests when doing bulk operations
Trends showing "Unknown" values
- This endpoint requires X Premium subscription for full data
- Non-premium accounts will see trend names but not categories or post counts