twitter-skillv1.0.0latest
by ryan321
Post tweets, reply, search, read timelines, like, retweet, and look up users on Twitter/X. Uses the official API v2 via the twitter-api-v2 SDK. Free tier supports posting and deleting; Basic tier ($200/mo) adds search, timelines, and engagement.
Install
https://clawskills.io/api/skills/twitter-skill/releases/1.0.0/SKILL.mdGive this URL to your OpenClaw agent to install.
Agent prompt
Fetch the skill from https://clawskills.io/api/skills/twitter-skill/releases/1.0.0/SKILL.md and follow its Quick Start section to install, configure, and verify the twitter-skill skill (v1.0.0).
Or copy this full prompt to give your agent.
SKILL.md
---
name: twitter-skill
version: 1.0.0
url: https://clawskills.io/api/skills/twitter-skill/releases/1.0.0/SKILL.md
artifact_sha256: 2dc550634a4dad60056ee9daabdaab4dcda0313163cbad0d412c6a3b60d7e154
signature: 7FTc0IJR3g3EraZEDxEXS+l6gaAsg7UvDpNL0Chn3F8ypVJn8U3DSUVR3FN8pzlXt7y2HimDhB8v7iuI9yM+Dg==
key_id: 625b196966442b38cf1c7188ba15fa81
verify: https://clawskills.io/docs/verification
---
# Twitter (X) Skill
Post tweets, search tweets, read timelines, and manage engagement on Twitter/X using the official API v2 via the `twitter-api-v2` SDK.
---
## Overview
- **What it does:**
Lets an AI agent read and write to Twitter/X — post tweets, reply, search, read timelines, like, retweet, and look up users via the `twitter-api-v2` Node.js SDK.
- **When to use it:**
When the user wants to interact with Twitter/X: posting updates, monitoring mentions, searching for topics, or engaging with tweets.
- **Requirements:**
- OS: macOS / Linux / Windows
- Runtime: Node.js 18+
- Accounts: Twitter/X developer account with API v2 access
- API tier: **Free** ($0) supports posting, deleting, and authenticated user lookup only. **Basic** ($200/mo) required for search, timelines, likes, retweets, and user lookups.
---
## Quick start
### Install
```bash
npm install twitter-api-v2@1.29.0
```
### Configure
Add your credentials in the **OpenClaw runtime environment** (Control UI env editor if available, process env, or `.env`):
```bash
# Required — set in OpenClaw runtime environment:
# TWITTER_API_KEY — your app's API key (Consumer Key)
# TWITTER_API_SECRET — your app's API secret (Consumer Secret)
# TWITTER_ACCESS_TOKEN — user-level access token
# TWITTER_ACCESS_SECRET — user-level access token secret
#
# Get your keys from: https://developer.x.com/en/portal/dashboard
```
### Verify
```bash
node -e "const{TwitterApi}=require('twitter-api-v2');new TwitterApi({appKey:process.env.TWITTER_API_KEY,appSecret:process.env.TWITTER_API_SECRET,accessToken:process.env.TWITTER_ACCESS_TOKEN,accessSecret:process.env.TWITTER_ACCESS_SECRET}).v2.me().then(u=>console.log(JSON.stringify(u.data,null,2)))"
```
**Expected result:**
Prints JSON with your authenticated user's `id`, `name`, and `username`.
---
## Core tasks
### Post a tweet
```text
Post a tweet saying "Hello from my agent!"
```
### Reply to a tweet
```text
Reply to tweet ID 1234567890 with the text "Great point, thanks for sharing!"
```
### Search recent tweets
```text
Search Twitter for recent tweets about "artificial intelligence" and show the top 10 results with timestamps and engagement metrics.
```
*Requires Basic tier ($200/mo) or higher.*
### Get home timeline
```text
Show the 10 most recent tweets from my home timeline, including timestamps and engagement metrics.
```
*Requires Basic tier ($200/mo) or higher.*
### Like a tweet
```text
Like the tweet with ID 1234567890.
```
*Requires Basic tier ($200/mo) or higher.*
### Retweet
```text
Retweet the tweet with ID 1234567890.
```
*Requires Basic tier ($200/mo) or higher.*
### Look up a user by username
```text
Look up the Twitter user @elonmusk and show their bio, follower count, and account creation date.
```
*Requires Basic tier ($200/mo) or higher.*
### Get a user's recent tweets
```text
Show the 10 most recent tweets from @elonmusk, including timestamps and engagement metrics.
```
*Requires Basic tier ($200/mo) or higher.*
### Delete a tweet
```text
Delete the tweet with ID 1234567890.
```
### Post a thread
```text
Post a Twitter thread with these parts: 1) "First tweet of the thread" 2) "Second tweet continues the thought" 3) "Final tweet wraps it up"
```
---
## SDK usage reference
This skill uses the `twitter-api-v2` npm package (no MCP server). The agent must write Node.js code to interact with the Twitter API. Below is the complete reference for constructing the client and calling each endpoint.
### Client initialization
```javascript
const { TwitterApi } = require('twitter-api-v2');
const client = new TwitterApi({
appKey: process.env.TWITTER_API_KEY,
appSecret: process.env.TWITTER_API_SECRET,
accessToken: process.env.TWITTER_ACCESS_TOKEN,
accessSecret: process.env.TWITTER_ACCESS_SECRET,
});
```
### Get authenticated user (Free tier)
```javascript
const { data: me } = await client.v2.me();
// me => { id: '123', name: 'Display Name', username: 'handle' }
```
Note: many methods below require the authenticated user's ID. Call `.me()` first and store `me.id`.
### Post a tweet (Free tier)
```javascript
const { data } = await client.v2.tweet('Hello world!');
// data => { id: '1234567890', text: 'Hello world!' }
```
With options:
```javascript
const { data } = await client.v2.tweet({
text: 'Tweet with options',
poll: { options: ['Yes', 'No'], duration_minutes: 60 },
});
```
### Reply to a tweet (Free tier)
```javascript
const { data } = await client.v2.reply('My reply text', '1234567890');
// '1234567890' is the tweet ID being replied to
```
### Delete a tweet (Free tier)
```javascript
const { data } = await client.v2.deleteTweet('1234567890');
// data => { deleted: true }
```
### Post a thread (Free tier)
```javascript
const results = await client.v2.tweetThread([
'First tweet in the thread',
'Second tweet continues the thought',
'Final tweet wraps it up',
]);
// results => array of TweetV2PostTweetResult
```
### Search recent tweets (Basic tier required)
```javascript
const results = await client.v2.search('artificial intelligence', {
max_results: 10,
'tweet.fields': ['created_at', 'public_metrics', 'author_id'],
});
for await (const tweet of results) {
// tweet => { id, text, created_at, public_metrics: { like_count, retweet_count, reply_count, impression_count }, author_id }
}
```
### Get home timeline (Basic tier required)
```javascript
const timeline = await client.v2.homeTimeline({
max_results: 10,
'tweet.fields': ['created_at', 'public_metrics', 'author_id'],
});
for await (const tweet of timeline) {
// tweet => { id, text, created_at, public_metrics, author_id }
}
```
### Get a user's tweets (Basic tier required)
```javascript
const tweets = await client.v2.userTimeline('USER_ID', {
max_results: 10,
'tweet.fields': ['created_at', 'public_metrics'],
});
for await (const tweet of tweets) {
// tweet => { id, text, created_at, public_metrics }
}
```
### Like a tweet (Basic tier required)
```javascript
const { data: me } = await client.v2.me();
await client.v2.like(me.id, '1234567890');
```
### Unlike a tweet (Basic tier required)
```javascript
const { data: me } = await client.v2.me();
await client.v2.unlike(me.id, '1234567890');
```
### Retweet (Basic tier required)
```javascript
const { data: me } = await client.v2.me();
await client.v2.retweet(me.id, '1234567890');
```
### Unretweet (Basic tier required)
```javascript
const { data: me } = await client.v2.me();
await client.v2.unretweet(me.id, '1234567890');
```
### Look up a user by username (Basic tier required)
```javascript
const { data: user } = await client.v2.userByUsername('elonmusk', {
'user.fields': ['description', 'public_metrics', 'created_at', 'profile_image_url'],
});
// user => { id, name, username, description, public_metrics: { followers_count, following_count, tweet_count }, created_at }
```
### Look up multiple users (Basic tier required)
```javascript
const { data: users } = await client.v2.usersByUsernames(['user1', 'user2'], {
'user.fields': ['description', 'public_metrics'],
});
```
### Get a single tweet by ID (Basic tier required)
```javascript
const { data: tweet } = await client.v2.singleTweet('1234567890', {
'tweet.fields': ['created_at', 'public_metrics', 'author_id'],
});
```
### Get user's mention timeline (Basic tier required)
```javascript
const { data: me } = await client.v2.me();
const mentions = await client.v2.userMentionTimeline(me.id, {
max_results: 10,
'tweet.fields': ['created_at', 'public_metrics'],
});
```
### API tier summary
| Operation | Free ($0) | Basic ($200/mo) |
|---|---|---|
| Post tweet | 1,500/mo app-level | 10,000/24h |
| Delete tweet | Yes | Yes |
| Get authenticated user (`me`) | Yes | Yes |
| Reply to tweet | Yes | Yes |
| Post thread | Yes | Yes |
| Search tweets | No | 450 req/15min |
| Home timeline | No | Yes |
| User timeline | No | 900 req/15min |
| Like / unlike | No | 50 req/15min |
| Retweet / unretweet | No | 50 req/15min |
| User lookup | No | 300 req/15min |
| Single tweet lookup | No | Yes |
| Mention timeline | No | Yes |
### Error handling pattern
```javascript
try {
const { data } = await client.v2.tweet('Hello!');
console.log('Posted:', data.id);
} catch (err) {
if (err.code === 429) {
// Rate limited — inform the user and wait
const resetTime = err.rateLimit?.reset;
console.error(`Rate limited. Resets at ${new Date(resetTime * 1000).toISOString()}`);
} else if (err.code === 401) {
console.error('Authentication failed — check credentials');
} else if (err.code === 403) {
console.error('Forbidden — check API tier and permissions');
} else {
console.error('Twitter API error:', err.message);
}
}
```
---
## Environment variable contract
| Variable | Purpose | Required | Where to set |
|---|---|---|---|
| `TWITTER_API_KEY` | API key / Consumer Key | Yes | OpenClaw runtime environment |
| `TWITTER_API_SECRET` | API secret / Consumer Secret | Yes | OpenClaw runtime environment |
| `TWITTER_ACCESS_TOKEN` | User-level OAuth 1.0a access token | Yes | OpenClaw runtime environment |
| `TWITTER_ACCESS_SECRET` | User-level OAuth 1.0a access token secret | Yes | OpenClaw runtime environment |
Credentials set in the OpenClaw runtime environment are automatically available to scripts executed by the agent.
---
## Configuration
* **Secrets / credentials required:**
* `TWITTER_API_KEY` — your app's API key (Consumer Key) from the X Developer Portal
* `TWITTER_API_SECRET` — your app's API secret (Consumer Secret)
* `TWITTER_ACCESS_TOKEN` — user-level access token (OAuth 1.0a)
* `TWITTER_ACCESS_SECRET` — user-level access token secret (OAuth 1.0a)
* **How to obtain credentials:**
1. Go to https://developer.x.com/en/portal/dashboard
2. Create a project and app
3. Under "Keys and tokens", generate API Key & Secret
4. Under "Authentication tokens", generate Access Token & Secret (with read+write permissions)
5. Free tier allows posting and deleting only. Upgrade to Basic ($200/mo) for search, timelines, likes, retweets, and user lookups.
* **Config files used:**
* No config files — this is an SDK-only skill. Credentials are read from environment variables at runtime.
* **How to reset / re-auth:**
* Regenerate tokens in the X Developer Portal under your app's "Keys and tokens" tab
* Update your environment variables with the new values
* Re-run the Verify command to confirm
---
## Security & Guardrails
### Secrets handling
* Never paste API keys, tokens, or secrets into chat.
* Always use environment variables (`TWITTER_API_KEY`, etc.).
* If authentication fails with a 401 or 403, recommend the user regenerate and rotate their credentials immediately — the old ones may be compromised.
* Never pass credentials as command-line arguments (visible in `ps` output).
### Confirmations (before risky actions)
* Always confirm with the user before:
* Posting a tweet or reply (content goes public immediately)
* Retweeting (visible to all followers)
* Deleting a tweet (irreversible)
* Liking tweets in bulk (may trigger rate limits or look like bot behavior)
* Show the user the exact text that will be posted before sending.
### Rate limits
* Twitter API v2 enforces strict rate limits per endpoint and tier.
* Free tier: ~1,500 posts per month at app level.
* Basic tier: standard 15-minute rate windows (see API tier summary above).
* Do not retry aggressively on 429 responses — check `err.rateLimit.reset` for the reset timestamp and inform the user.
* Prefer batched lookups (`client.v2.tweets([id1, id2])`) over individual calls when possible.
### Data minimization
* Return summaries by default — don't dump full API responses unless the user asks.
* Avoid logging or echoing tokens in output.
* When searching, use `max_results: 10` unless the user requests more.
* Strip unnecessary metadata from responses before presenting to the user.
### Permissions / scopes
* **Required OAuth 1.0a permissions:** Read and Write.
* **Least privilege:** If the user only needs to read (search, timelines, lookups), a read-only app is sufficient. Only enable write access when posting, liking, or retweeting is needed.
### Network access
* **Domains used:**
* `api.twitter.com` — all Twitter API v2 requests
* `api.x.com` — alias for the same API
### Local storage
* **Writes to:** Nothing — this skill does not write to the filesystem beyond the installed npm package in `node_modules/`.
* **Does not access:** SSH keys, browser profiles, keychains, password stores, or any local files.
### Revoke / rotate
* Revoke tokens: X Developer Portal > Your App > Keys and tokens > Regenerate (old tokens are immediately invalidated).
* Rotate tokens: Generate new Access Token & Secret, update environment variables, re-run the Verify command.
---
## Troubleshooting
* **Error:** `401 Unauthorized`
* Fix: Check that all four environment variables are set and correct. Regenerate tokens in the X Developer Portal if needed.
* **Error:** `403 Forbidden - client-not-enrolled`
* Fix: Your developer account may not have API v2 access enabled, or the endpoint requires a higher tier. Free tier only supports posting, deleting, and user self-lookup. Upgrade to Basic ($200/mo) for search, timelines, likes, retweets, and user lookups.
* **Error:** `403 Forbidden` on like/retweet/search
* Fix: These endpoints are not available on the Free tier. The user needs to upgrade to Basic tier ($200/mo) in the X Developer Portal.
* **Error:** `429 Too Many Requests`
* Fix: Rate limit exceeded. Check the `rateLimit.reset` timestamp in the error response for when the window resets (typically 15 minutes). Do not retry aggressively.
* **Error:** `ENOTFOUND api.twitter.com`
* Fix: Check your network connection. If behind a proxy, configure `https_proxy` environment variable.
* **Problem:** "Tweet text too long"
* Fix: Tweets are limited to 280 characters. Use `client.v2.tweetThread()` to split into a thread.
---
## Release notes
* v1.0.0:
* Initial release
* Post, reply, delete, thread, search, timeline, like, retweet, user lookup
* Uses `twitter-api-v2@1.29.0`
* Documents Free vs Basic tier limitations
---
## Links
* Package: https://www.npmjs.com/package/twitter-api-v2
* Package repo: https://github.com/PLhery/node-twitter-api-v2
* SDK documentation: https://github.com/PLhery/node-twitter-api-v2/blob/master/doc/v2.md
* API docs: https://developer.x.com/en/docs/twitter-api
* Developer portal: https://developer.x.com/en/portal/dashboard
* Rate limits reference: https://developer.x.com/en/docs/twitter-api/rate-limits
* API tier comparison: https://developer.x.com/en/docs/twitter-api/getting-started/about-twitter-api
---
## Publisher
* **Publisher:** @Agentopolis
Security Guardrails
secrets/credential handlingconfirmation before risky actionsrate limitingdata minimizationpermissions/scopesnetwork access disclosurelocal storage disclosuretoken revocation/rotation
Releases
1.0.0listedcurrent
2/15/2026External Interfaces
Secrets & Environment Variables
TWITTER_API_KEYTWITTER_API_SECRETTWITTER_ACCESS_TOKENTWITTER_ACCESS_SECRET
Packages
npm install twitter-api-v2@1.29.0
Languages
javascript
Network Domains
localhostdeveloper.x.comwww.npmjs.comgithub.com
File System Access
~/.openclaw/openclaw.json
Files Included (1)
SKILL.md15.5 KB