Matt Jackson ab32ef4cc2 Fix login flow: adaptive page reading, keyboard.type, session cleanup
- Adaptive login loop reads page state each step and responds accordingly
- Switched from fill() to keyboard.type() for anti-detection
- Navigate to /compose/post for posting instead of sidebar button
- Clean up stale browser sessions before creating new ones
- Fixed +1 country code for phone verification

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 23:39:13 +00:00
2026-03-07 23:19:59 +00:00
2026-03-07 23:19:59 +00:00

xBot

AI-powered Twitter/X bot that generates and posts tweets on configurable schedules using stealth browser automation.

How it works

  1. Scheduler runs via cron, picks random times within a configured window
  2. Bot logs into X via Kernel.sh stealth browsers (residential proxies + CAPTCHA solving)
  3. Claude (Anthropic API) generates tweets based on your prompts
  4. Links are inserted after generation — URLs never touch the AI
  5. History is tracked per-prompt and fed back to avoid repetition

Setup

Prerequisites

Install

git clone https://github.com/MattJackson/xBot.git
cd xBot
npm install

Configure

  1. Copy the example files:
cp .env.example .env
cp prompts.example.json prompts.json
  1. Edit .env with your credentials:
MYACCOUNT_USER=your_twitter_handle
MYACCOUNT_PW=your_password
MYACCOUNT_EMAIL=your_email@example.com
MYACCOUNT_PHONE=1234567890

KERNEL=sk_your_kernel_key
ANTHROPIC=sk-ant-your_anthropic_key

Credentials are prefixed by account name (uppercase). To add another account, add another set:

ANOTHERACCOUNT_USER=...
ANOTHERACCOUNT_PW=...
ANOTHERACCOUNT_EMAIL=...
ANOTHERACCOUNT_PHONE=...
  1. Edit prompts.json with your prompts (see Prompt Configuration below).

Run

Post a single tweet:

node bot.js <prompt-name>

Schedule posts for the day (picks random times, waits, then posts):

node scheduler.js <prompt-name>

Cron

Add a cron job for each prompt. The scheduler handles random timing within the window — cron just needs to trigger it once daily before the window opens.

crontab -e
# Runs daily — scheduler picks random time(s) between 8am-8pm PST
0 16 * * * cd /path/to/xBot && /usr/bin/node scheduler.js my-prompt >> bot.log 2>&1

The cron time should be in UTC. 0 16 * * * = midnight PST (8 hours ahead), ensuring the scheduler starts before the 8am PST window.

Prompt Configuration

prompts.json is an array of prompt objects:

[
  {
    "name": "my-prompt",
    "account": "myaccount",
    "prompt": "Your prompt text here. Generate 1 tweet. Just the tweet.",
    "links": {
      "link": "https://example.com"
    },
    "schedule": {
      "type": "daily",
      "window": [8, 20],
      "postsPerDay": [1, 3],
      "minGapHours": 4
    }
  }
]

Fields

Field Required Description
name Yes Unique identifier. Used as CLI argument and for history files.
account Yes Maps to env var prefix. "myaccount" looks up MYACCOUNT_USER, etc.
prompt Yes The prompt sent to Claude. Include generation instructions here.
links No Key-value map. <key> placeholders in the generated tweet are replaced with the URL. URLs never reach the AI.
schedule Yes Scheduling configuration (see below).

Schedule types

Daily — posts every day, 1 or more times:

{
  "type": "daily",
  "window": [8, 20],
  "postsPerDay": [1, 3],
  "minGapHours": 4
}
  • window: [startHour, endHour] in PST. Posts only happen within this range.
  • postsPerDay: [min, max]. A random count is picked each day. Defaults to [1, 1].
  • minGapHours: Minimum hours between posts on the same day. Defaults to 4.

Random — posts on random days with a minimum gap:

{
  "type": "random",
  "window": [8, 20],
  "minDays": 2
}
  • minDays: Minimum days between posts. After the gap is met, there's a 50% chance each day — so actual spacing varies naturally (2, 3, 4+ days).

Use <placeholder> in your prompt instructions. The AI generates the tweet with the placeholder, then the bot replaces it with the real URL:

{
  "prompt": "Write a tweet. End with <link> on its own line.",
  "links": {
    "link": "https://example.com"
  }
}

Multiple placeholders work too:

{
  "prompt": "Mention <site> and end with <cta>.",
  "links": {
    "site": "https://mysite.com",
    "cta": "https://mysite.com/signup"
  }
}

Multi-account

Each prompt specifies which account to post from. You can run multiple accounts from the same instance:

[
  { "name": "account1-daily", "account": "firstaccount", "prompt": "...", "schedule": { ... } },
  { "name": "account2-promo", "account": "secondaccount", "prompt": "...", "schedule": { ... } }
]

Just add the corresponding credentials to .env for each account.

Files

File Tracked Description
bot.js Yes Main bot — login, generate, post
scheduler.js Yes Picks random times, runs bot.js
prompts.json No Your prompt config (create from example)
.env No Your credentials
history-*.json No Per-prompt tweet history
bot.log No Cron output log

License

MIT

Description
Config-driven Twitter/X bot powered by AI tweet generation and stealth browser automation
Readme MIT 50 KiB
Languages
JavaScript 81.1%
Shell 18%
Dockerfile 0.9%