plugins/plugin-x/README.md
This package provides Twitter/X integration for the Eliza AI agent using the official Twitter API v2.
Just want your bot to post tweets? Here's the fastest path:
Get Twitter Developer account β https://developer.twitter.com
Create an app β Enable "Read and write" permissions
Choose your auth mode:
Option A (default, legacy): OAuth 1.0a env vars
Option B (recommended): βlogin + approveβ OAuth 2.0 (PKCE)
Add to .env:
# Option A: legacy OAuth 1.0a (default)
TWITTER_AUTH_MODE=env
TWITTER_API_KEY=xxx
TWITTER_API_SECRET_KEY=xxx
TWITTER_ACCESS_TOKEN=xxx
TWITTER_ACCESS_TOKEN_SECRET=xxx
# Option B: OAuth 2.0 PKCE (interactive login + approve, no client secret)
# TWITTER_AUTH_MODE=oauth
# TWITTER_CLIENT_ID=xxx
# TWITTER_REDIRECT_URI=http://127.0.0.1:8080/callback
TWITTER_ENABLE_POST=true
TWITTER_POST_IMMEDIATELY=true
Run: bun start
Tip: if you use OAuth 2.0 PKCE, the plugin will print an authorization URL on first run and store tokens for you (no manual token pasting).
β οΈ CRITICAL: Default apps can only READ. You must enable WRITE permissions to post tweets!
In your app settings, go to "User authentication settings"
Configure exactly as shown:
App permissions: Read and write β
Type of App: Web App, Automated App or Bot
Required URLs (copy these exactly):
Callback URI: http://localhost:3000/callback
Website URL: https://github.com/elizaos/eliza
Optional fields:
Organization name: ElizaOS
Organization URL: https://github.com/elizaos/eliza
Click Save
You can use either legacy OAuth 1.0a env vars (default) or OAuth 2.0 PKCE (βlogin + approveβ).
In your app's "Keys and tokens" page, you'll see several sections. Here's what to use:
β
USE THESE when TWITTER_AUTH_MODE=env (OAuth 1.0a):
βββββββββββββββββββββββββββββββββββββββββββββββββββ
β Consumer Keys β
β ββ API Key: xxx...xxx β TWITTER_API_KEY β
β ββ API Key Secret: xxx...xxx β TWITTER_API_SECRET_KEY β
β β
β Authentication Tokens β
β ββ Access Token: xxx...xxx β TWITTER_ACCESS_TOKEN β
β ββ Access Token Secret: xxx β TWITTER_ACCESS_TOKEN_SECRET β
βββββββββββββββββββββββββββββββββββββββββββββββββββ
β
USE THESE when TWITTER_AUTH_MODE=oauth (OAuth 2.0 PKCE):
βββββββββββββββββββββββββββββββββββββββββββββββββββ
β OAuth 2.0 Client ID and Client Secret β
β ββ Client ID: xxx...xxx β TWITTER_CLIENT_ID β
β ββ Client Secret: xxx...xxx β NOT USED (do not put in env) β
β β
β Bearer Token β NOT USED β
βββββββββββββββββββββββββββββββββββββββββββββββββββ
After enabling write permissions, you MUST:
Create or edit .env file in your project root:
# Auth mode (default: env)
# - env: legacy OAuth 1.0a keys/tokens
# - oauth: βlogin + approveβ OAuth 2.0 PKCE (no client secret in plugin)
TWITTER_AUTH_MODE=env
TWITTER_DEFAULT_ACCOUNT_ID=default
# REQUIRED: OAuth 1.0a Credentials (from "Consumer Keys" section)
TWITTER_API_KEY=your_api_key_here # From "API Key"
TWITTER_API_SECRET_KEY=your_api_key_secret_here # From "API Key Secret"
# REQUIRED: OAuth 1.0a Tokens (from "Authentication Tokens" section)
TWITTER_ACCESS_TOKEN=your_access_token_here # Must have "Read and Write"
TWITTER_ACCESS_TOKEN_SECRET=your_token_secret_here # Regenerate after permission change
# ---- OR ----
# OAuth 2.0 PKCE (βlogin + approveβ) configuration:
# TWITTER_AUTH_MODE=oauth
# TWITTER_CLIENT_ID=your_oauth2_client_id_here
# TWITTER_REDIRECT_URI=http://127.0.0.1:8080/callback
# Optional:
# TWITTER_SCOPES="tweet.read tweet.write users.read offline.access"
# Basic Configuration
TWITTER_DRY_RUN=false # Set to true to test without posting
TWITTER_ENABLE_POST=true # Enable autonomous tweet posting
# Optional: Posting Configuration
TWITTER_POST_IMMEDIATELY=true # Post on startup (great for testing)
TWITTER_POST_INTERVAL=120 # Minutes between posts (default: 120)
# For more natural timing, use MIN/MAX intervals:
TWITTER_POST_INTERVAL_MIN=90 # Minimum minutes between posts
TWITTER_POST_INTERVAL_MAX=150 # Maximum minutes between posts
When using TWITTER_AUTH_MODE=oauth, the plugin will:
accountId via Eliza runtime cache if available, otherwise a local token file under ~/.eliza/twitter/accounts/<accountId>/oauth2.tokens.jsonFor multi-account pilots, route connector targets with accountId. The plugin defaults to TWITTER_DEFAULT_ACCOUNT_ID when no target/content account is provided. You can also provide account-scoped credentials through TWITTER_ACCOUNTS JSON until the shared connector account store is available.
// Your character should include the twitter plugin
const character = {
// ... other config
plugins: [
// Required for content generation
"@elizaos/plugin-x", // X (Twitter) functionality
],
postExamples: [
// Examples for tweet generation
"Just discovered an amazing pattern in the data...",
"The future of AI is collaborative intelligence",
// ... more examples
],
};
Then start your bot:
bun run start
# Required Twitter API v2 Credentials (OAuth 1.0a)
TWITTER_API_KEY= # Consumer API Key
TWITTER_API_SECRET_KEY= # Consumer API Secret
TWITTER_ACCESS_TOKEN= # Access Token (with write permissions)
TWITTER_ACCESS_TOKEN_SECRET= # Access Token Secret
# Core Configuration
TWITTER_DRY_RUN=false # Set to true for testing without posting
TWITTER_TARGET_USERS= # Comma-separated usernames to target (use "*" for all)
TWITTER_RETRY_LIMIT=5 # Maximum retry attempts for failed operations
# Feature Toggles
TWITTER_ENABLE_POST=false # Enable autonomous tweet posting
TWITTER_ENABLE_REPLIES=true # Enable mention and reply handling
TWITTER_ENABLE_ACTIONS=false # Enable timeline actions (likes, retweets, quotes)
TWITTER_ENABLE_DISCOVERY= # Enable discovery service (defaults to true if ACTIONS enabled)
# Timing Configuration (all in minutes)
# For natural behavior, set MIN/MAX intervals - the agent will randomly choose between them
# If MIN/MAX not set, falls back to the fixed interval values
# Post intervals
TWITTER_POST_INTERVAL=120 # Fixed interval between posts (default: 120, used if MIN/MAX not set)
TWITTER_POST_INTERVAL_MIN=90 # Minimum minutes between posts (default: 90)
TWITTER_POST_INTERVAL_MAX=150 # Maximum minutes between posts (default: 150)
# Engagement intervals
TWITTER_ENGAGEMENT_INTERVAL=30 # Fixed interval for interactions (default: 30, used if MIN/MAX not set)
TWITTER_ENGAGEMENT_INTERVAL_MIN=20 # Minimum minutes between engagements (default: 20)
TWITTER_ENGAGEMENT_INTERVAL_MAX=40 # Maximum minutes between engagements (default: 40)
# Discovery intervals
TWITTER_DISCOVERY_INTERVAL_MIN=15 # Minimum minutes between discovery cycles (default: 15)
TWITTER_DISCOVERY_INTERVAL_MAX=30 # Maximum minutes between discovery cycles (default: 30)
# Engagement Limits
TWITTER_MAX_ENGAGEMENTS_PER_RUN=5 # Maximum interactions per engagement cycle (default: 5)
TWITTER_MAX_TWEET_LENGTH=280 # Maximum tweet length
# Discovery Service Settings
TWITTER_MIN_FOLLOWER_COUNT=100 # Minimum followers for accounts to follow
TWITTER_MAX_FOLLOWS_PER_CYCLE=5 # Maximum accounts to follow per discovery cycle
The Twitter Discovery Service enables autonomous content discovery and engagement, helping your agent build a following and interact with relevant content on Twitter.
The discovery service autonomously:
# Enable discovery service (defaults to true if TWITTER_ENABLE_ACTIONS=true)
TWITTER_ENABLE_DISCOVERY=true
# Discovery interval in minutes (default: 30)
TWITTER_DISCOVERY_INTERVAL=30
# Minimum follower count for accounts to follow (default: 100)
TWITTER_MIN_FOLLOWER_COUNT=100
# Maximum accounts to follow per cycle (default: 5)
TWITTER_MAX_FOLLOWS_PER_CYCLE=5
# Maximum engagements per cycle (default: 10)
TWITTER_MAX_ENGAGEMENTS_PER_RUN=10
The discovery service uses your agent's character configuration:
{
"name": "YourAgent",
"topics": [
"artificial intelligence",
"machine learning",
"web3",
"blockchain"
],
"bio": "AI researcher interested in decentralized systems"
}
If topics aren't specified, the service extracts them from the bio.
# Minimal setup for posting only
TWITTER_API_KEY=xxx
TWITTER_API_SECRET_KEY=xxx
TWITTER_ACCESS_TOKEN=xxx # Must have write permissions!
TWITTER_ACCESS_TOKEN_SECRET=xxx
TWITTER_ENABLE_POST=true
TWITTER_POST_IMMEDIATELY=true # Great for testing
TWITTER_ENABLE_REPLIES=false # Disable interactions
TWITTER_ENABLE_ACTIONS=false # Disable timeline actions
# Full interaction setup
TWITTER_API_KEY=xxx
TWITTER_API_SECRET_KEY=xxx
TWITTER_ACCESS_TOKEN=xxx
TWITTER_ACCESS_TOKEN_SECRET=xxx
TWITTER_ENABLE_POST=true
TWITTER_ENABLE_REPLIES=true
TWITTER_ENABLE_ACTIONS=true # Enables likes, retweets, quotes
TWITTER_ENABLE_DISCOVERY=true # Enables growth features
# Dry run mode
TWITTER_DRY_RUN=true # Simulates all actions
TWITTER_ENABLE_POST=true
TWITTER_POST_IMMEDIATELY=true
If you see errors like "Failed to create tweet: Request failed with code 403", this usually means:
Missing Write Permissions: Make sure your Twitter app has "Read and write" permissions
Protected Accounts: The bot may be trying to engage with protected/private accounts
Self-Engagement: Trying to reply to or quote your own tweets
Account Restrictions: Your account may have restrictions
The plugin will now:
This is the #1 issue! Your app has read-only permissions.
Solution:
.env with NEW tokensHow to verify: In "Keys and tokens", your Access Token should show "Created with Read and Write permissions"
This usually means your credentials donβt match your selected auth mode.
Solution:
TWITTER_AUTH_MODE=env:
TWITTER_AUTH_MODE=oauth:
TWITTER_CLIENT_ID)TWITTER_REDIRECT_URI, e.g. http://127.0.0.1:8080/callback)Checklist:
TWITTER_ENABLE_POST=true?postExamples?TWITTER_POST_IMMEDIATELY=true for testingCommon causes:
Your tokens may have been revoked or regenerated.
Solution:
.envThe plugin supports two main approaches:
# Interact with everyone (default)
TWITTER_TARGET_USERS=
# Interact with specific users only
TWITTER_TARGET_USERS=user1,user2,user3
# Interact with everyone (explicit)
TWITTER_TARGET_USERS=*
The plugin adds variance to all intervals for more human-like behavior:
The plugin includes sophisticated rate limiting:
# Run tests
bun test
# Run with debug logging
DEBUG=eliza:* bun start
# Test without posting
TWITTER_DRY_RUN=true bun start
TWITTER_POST_IMMEDIATELY=trueTWITTER_DRY_RUN=true first.env file (never commit!).env.local for local developmentThis plugin uses Twitter API v2 endpoints efficiently:
Monitor your usage at: https://developer.twitter.com/en/portal/dashboard
Contributions are welcome! Please:
This plugin is part of the ElizaOS project. See the main repository for license information.