Twitter/X Bot Development for Crypto Projects
We've been building Twitter/X bots for crypto projects since the early days of the crypto market. Over this time, we've launched more than 20 solutions for on-chain monitoring, automated announcements, and metric digests. Twitter/X remains the primary platform for the crypto community—alpha spreads here faster than anywhere else. Bots solve specific tasks: alerts for large transactions, liquidations, DAO votes, and scheduled protocol metric publications. Telegram bots are easier to implement, but Twitter offers public visibility and narrative influence.
Twitter API v2 Limitations
Recent changes to Twitter/X have modified API conditions. Understanding current limits is critical. Consider the pricing plans:
| Plan | Tweets per month | Reads per month | Suitable for |
|---|---|---|---|
| Free | 1,500 | 800,000 | Testing only |
| Basic | 3,000 | 10,000 | Bots with moderate activity |
| Pro | 300,000 | 1,000,000 | High-frequency alert bots |
For most crypto projects, Basic is sufficient. But if you plan to tweet every large transaction on a popular protocol, monthly volume can reach hundreds of tweets per day. Calculate your limit in advance.
How We Build the Bot Architecture
Component 1: On-chain Monitor
Data source—blockchain events via WebSocket. We don't use third-party aggregators—they add latency. Subscribe to events in real-time:
const { ethers } = require('ethers') const provider = new ethers.WebSocketProvider(process.env.WSS_RPC_URL) const AAVE_POOL = '0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2' const LIQUIDATION_TOPIC = ethers.id('LiquidationCall(address,address,address,uint256,uint256,address,bool)') provider.on({ address: AAVE_POOL, topics: [LIQUIDATION_TOPIC] }, async (log) => { const iface = new ethers.Interface(AAVE_POOL_ABI) const decoded = iface.parseLog(log) const collateralAsset = decoded.args.collateralAsset const debtAsset = decoded.args.debtAsset const liquidatedCollateralAmount = decoded.args.liquidatedCollateralAmount const usdValue = await getUSDValue(collateralAsset, liquidatedCollateralAmount) if (usdValue > MINIMUM_NOTABLE_USD) { await postLiquidationTweet({ collateralAsset, debtAsset, usdValue, txHash: log.transactionHash }) } }) Component 2: Formatting and Publishing
const { TwitterApi } = require('twitter-api-v2') const client = new TwitterApi({ appKey: process.env.TWITTER_APP_KEY, appSecret: process.env.TWITTER_APP_SECRET, accessToken: process.env.TWITTER_ACCESS_TOKEN, accessSecret: process.env.TWITTER_ACCESS_SECRET, }) const rwClient = client.readWrite async function postLiquidationTweet({ collateralAsset, debtAsset, usdValue, txHash }) { const collSymbol = await getTokenSymbol(collateralAsset) const debtSymbol = await getTokenSymbol(debtAsset) const text = [ `🔴 AAVE Liquidation`, ``, `Collateral: ${collSymbol}`, `Debt: ${debtSymbol}`, `Value: $${formatUSD(usdValue)}`, ``, `Tx: https://etherscan.io/tx/${txHash}`, ``, `#DeFi #AAVE #Liquidation` ].join('\n') try { await rwClient.v2.tweet(text) } catch (error) { if (error.code === 403) { // Duplicate tweet — add timestamp or skip logger.warn('Duplicate tweet prevented', { txHash }) } else { throw error } } } Why Use WebSocket Instead of REST?
REST requests add latency due to constant RPC polling. WebSocket provides event subscription—data arrives instantly. This is critical for bots reacting to liquidations or large transactions within seconds. Additionally, WebSocket reduces RPC load and infrastructure costs.
How to Protect the Bot from Suspension and Rate Limits
Twitter/X actively detects abnormal behavior. Our best practices:
- Deduplication: Store txHash of published events (Redis with 24h TTL)—never tweet the same event twice.
- Minimum delay between tweets: 30 seconds during event bursts.
- Priority queue: if many events occur, publish the largest ones and aggregate minor ones into a digest.
- Graceful reconnect: WebSocket connections break; use exponential backoff.
// Queue with debounce for batch events class TweetQueue { constructor(client, maxPerHour = 20) { this.queue = [] this.maxPerHour = maxPerHour this.published = [] // Publish every 3 minutes (max 20 per hour) setInterval(() => this.flush(), 3 * 60 * 1000) } async add(event) { if (this.queue.some(e => e.txHash === event.txHash)) return this.queue.push({ ...event, addedAt: Date.now() }) this.queue.sort((a, b) => b.usdValue - a.usdValue) } async flush() { if (this.queue.length === 0) return const toPublish = this.queue.shift() await this.client.v2.tweet(formatTweet(toPublish)) const lastHour = this.published.filter(t => Date.now() - t < 3600000) if (lastHour.length >= this.maxPerHour) { logger.info('Rate limit self-imposed, queuing') return } this.published.push(Date.now()) } } Can You Set Up Regular Digests?
Yes. In addition to event-driven publications, we configure periodic tweets with protocol metrics. For example, daily stats at 12:00 UTC:
const cron = require('node-cron') cron.schedule('0 12 * * *', async () => { const stats = await fetchProtocolStats() await rwClient.v2.tweet( `📊 Daily Stats — ${new Date().toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}\n\n` + `TVL: $${formatBigNumber(stats.tvl)}\n` + `24h Volume: $${formatBigNumber(stats.volume24h)}\n` + `Active Users: ${stats.activeUsers.toLocaleString()}\n\n` + `#DeFi` ) }) WebSocket vs REST for On-chain Monitoring
| Characteristic | WebSocket | REST |
|---|---|---|
| Latency | < 1s (push) | 12-15s (poll) |
| RPC load | Low | High (frequent requests) |
| Implementation complexity | Connection management required | Simpler |
| Suitable for | Real-time alerts | Historical data |
Deployment and Monitoring
Minimal infrastructure—Docker container on a VPS with a persistent WebSocket connection. Use PM2 or systemd for auto-restart. Logs via Winston to a file, plus optional Telegram alerts for bot errors. Environment variables—only .env file, in production use a secrets manager. We guarantee stable 24/7 operation.
What's Included in the Work
- Twitter Developer App setup and OAuth 2.0 authentication
- On-chain monitor with WebSocket subscription to target events
- Tweet formatting with real blockchain data
- Deduplication, rate limiting, priority queue
- Scheduled publications (digests, metrics)
- Deployment on VPS with process monitoring
Step-by-Step Bot Deployment Guide
- Create a Twitter Developer App and obtain API keys (OAuth 2.0).
- Choose an RPC provider with WebSocket support (e.g., Infura or Alchemy).
- Configure environment: place keys in
.env, install dependencies (npm install ethers twitter-api-v2 winston). - Run the bot locally:
node bot.jsand verify tweets are posted. - Deploy to VPS: use a Docker image or copy the project, run via
pm2 start bot.js --name cryptobot. - Set up monitoring: add error alerts via Telegram or Slack.
Deduplication Example with Redis
const redis = require('redis') const client = redis.createClient() async function isDuplicated(txHash) { const exists = await client.exists(txHash) if (exists) return true await client.set(txHash, '1', 'EX', 86400) // TTL 24h return false } According to official Twitter API v2 documentation, write limits for the Basic plan are 3,000 tweets per month. For most crypto projects this is sufficient—provided proper event filtering. Investment in bot development depends on the scope, but savings from timely liquidation alerts or large transaction notifications can recoup costs quickly.
Order Twitter/X bot development for your crypto project. Contact us—we'll assess your requirements and propose the optimal solution. Get a consultation right now.







