Skip to content

Twitter / X

Overview#

The Twitter / X integration lets your Cognest assistant post tweets, reply to conversations, retweet content, manage direct messages, and react to real-time events such as mentions and new followers. It wraps the X API v2 and handles rate limiting, pagination, and OAuth token management automatically.

Prerequisites#

  1. A Twitter Developer account with an approved project and app.
  2. Your app must have OAuth 1.0a enabled with read/write and direct-message permissions.
  3. Generate API keys, access tokens, and a bearer token from the Keys and Tokens tab in your Twitter app settings.
  4. Add the following variables to your .env file:
.env
TWITTER_API_KEY=your_api_key
TWITTER_API_SECRET=your_api_secret
TWITTER_ACCESS_TOKEN=your_access_token
TWITTER_ACCESS_SECRET=your_access_secret
TWITTER_BEARER_TOKEN=your_bearer_token

Configuration#

Add the Twitter integration to your cognest.config.yaml:

cognest.config.yaml
integrations:
  twitter:
    enabled: true
    credentials:
      api_key: ${TWITTER_API_KEY}
      api_secret: ${TWITTER_API_SECRET}
      access_token: ${TWITTER_ACCESS_TOKEN}
      access_secret: ${TWITTER_ACCESS_SECRET}
      bearer_token: ${TWITTER_BEARER_TOKEN}
    settings:
      # Poll interval for timeline and mention checks (seconds)
      poll_interval: 30
      # Maximum tweet length (default 280)
      max_tweet_length: 280
      # Enable filtered stream for real-time events
      use_filtered_stream: true
      # Rate limit strategy: "queue" buffers requests, "drop" discards excess
      rate_limit_strategy: queue

SDK Usage#

You can use the integration through the config file (shown above) or register it programmatically:

index.ts
import { Cognest } from '@cognest/sdk'

const cognest = new Cognest()
const twitter = cognest.integration('twitter')

await twitter.tweet('Hello from Cognest!')
await cognest.start()

Available Methods#

MethodParametersDescription
tweet(text, options?)text: string, options?: { mediaIds?, replySettings? }Post a new tweet. Supports media attachments and reply restrictions.
reply(tweetId, text, options?)tweetId: string, text: stringReply to an existing tweet by its ID.
retweet(tweetId)tweetId: stringRetweet (repost) an existing tweet.
like(tweetId)tweetId: stringLike a tweet.
getTimeline(userId?, options?)userId?: string, options?: { maxResults?, paginationToken? }Retrieve the home or user timeline. Defaults to the authenticated user.
searchTweets(query, options?)query: string, options?: { maxResults?, startTime?, endTime? }Search recent tweets matching a query using the X API v2 search endpoint.
getUser(username)username: stringFetch a user profile by handle.
sendDM(userId, text)userId: string, text: stringSend a direct message to a user.

Events#

Subscribe to real-time events emitted by the Twitter integration. Events are delivered through the filtered stream or polling, depending on your configuration.

EventPayloadDescription
mention{ tweetId, userId, username, text, createdAt }Fired when the authenticated account is mentioned in a tweet.
dm:received{ senderId, senderUsername, text, conversationId, createdAt }Fired when a new direct message is received.
tweet:liked{ tweetId, userId, username }Fired when one of your tweets is liked.
tweet:retweeted{ tweetId, userId, username }Fired when one of your tweets is retweeted.
follower:new{ userId, username, followedAt }Fired when a new user follows the authenticated account.
events.ts
twitter.on('mention', async (event) => {
  console.log(`@${event.username} mentioned you: ${event.text}`)

  // Auto-reply to mentions
  await twitter.reply(event.tweetId, `Thanks for the mention, @${event.username}!`)
})

twitter.on('dm:received', async (event) => {
  console.log(`DM from @${event.senderUsername}: ${event.text}`)
})

twitter.on('follower:new', async (event) => {
  console.log(`New follower: @${event.username}`)
})

Example#

A complete example that monitors brand mentions, performs sentiment analysis with the AI engine, and auto-replies to positive tweets:

bot.ts
import { Cognest } from '@cognest/sdk'

const cognest = new Cognest()
const twitter = cognest.integration('twitter')

// Monitor brand mentions and respond intelligently
twitter.on('mention', async (event) => {
  // Use the AI engine to analyze sentiment
  const analysis = await cognest.engine.run({
    prompt: `Analyze the sentiment of this tweet and decide if we should reply.
Tweet: "${event.text}"
If positive or neutral, draft a friendly reply under 280 characters.
If negative, draft a professional support-oriented reply.
Return JSON: { "sentiment": "positive"|"negative"|"neutral", "reply": "..." }`,
    responseFormat: 'json',
  })

  const { sentiment, reply } = JSON.parse(analysis.text)

  // Reply to the tweet
  await twitter.reply(event.tweetId, reply)

  // Log for analytics
  console.log(`[${sentiment}] @${event.username}: ${event.text}`)
  console.log(`  Replied: ${reply}`)
})

// Auto-retweet tweets from a curated list of accounts
const CURATED_ACCOUNTS = ['cognestai', 'techleaders', 'airesearchers']

cognest.skill('scheduled-retweet', {
  schedule: '0 */4 * * *', // Every 4 hours
  handler: async () => {
    for (const account of CURATED_ACCOUNTS) {
      const user = await twitter.getUser(account)
      const timeline = await twitter.getTimeline(user.id, { maxResults: 5 })

      for (const tweet of timeline.data) {
        // Only retweet if it matches our topic filter
        const isRelevant = await cognest.engine.run({
          prompt: `Is this tweet relevant to AI automation? Answer yes or no.\nTweet: "${tweet.text}"`,
        })

        if (isRelevant.text.toLowerCase().includes('yes')) {
          await twitter.retweet(tweet.id)
        }
      }
    }
  },
})

// Search for industry discussions and engage
cognest.skill('social-listening', {
  schedule: '*/15 * * * *', // Every 15 minutes
  handler: async () => {
    const results = await twitter.searchTweets(
      '"AI automation" OR "workflow automation" -is:retweet lang:en',
      { maxResults: 10 }
    )

    for (const tweet of results.data) {
      await twitter.like(tweet.id)
    }
  },
})

await cognest.start()
console.log('Twitter bot is running...')

Troubleshooting#

Common Issues

403 Forbidden: Your Twitter app may not have the required permissions. Go to the Twitter Developer Portal and ensure your app has Read and Write permissions, plus Direct Message access if using DMs. 429 Too Many Requests: You've hit a rate limit. Cognest queues requests by default when rate_limit_strategy is set to "queue". If you see this error, check your poll_interval and reduce request frequency. Filtered Stream connection drops: The X API v2 filtered stream has a maximum of one concurrent connection per app. Ensure only one Cognest instance is using the stream. Set use_filtered_stream: false to fall back to polling. Bearer token errors: The bearer token is used for app-only authentication (read-only). Posting tweets, liking, and DMs require OAuth 1.0a user tokens (access_token and access_secret).

Rate Limit Reference

The X API v2 free tier allows 1,500 tweets per month and 50 requests per 15-minute window for most endpoints. The Basic tier ($100/month) increases this to 3,000 tweets and 10,000 search results. Check your usage tier in the Developer Portal and configure poll_interval accordingly.