X-Tracker-Bot monitors who your chosen X / Twitter accounts follow and sends you an instant Discord notification the moment they follow someone new. Lightweight, single-binary, written in Go.
X-Tracker-Bot is a free, open-source tool that tracks new follows on X (formerly Twitter) and pushes real-time alerts to Discord via webhooks. It's perfect for alpha hunting, KOL tracking, project discovery, and competitor research — see what influential accounts follow before everyone else.
- What Is X-Tracker-Bot?
- Key Features
- What You Need Before Starting
- Installation Guide (Step by Step)
- Configuration Reference
- Running 24/7 (Keep It Always On)
- How It Works
- Troubleshooting
- FAQ
- Build from Source & Cross-Compile
- Tech Stack
- License
X-Tracker-Bot is a follow-tracking bot for X / Twitter. You give it a list of accounts to watch ("watchers"), and it continuously checks who those accounts follow. Whenever a watched account follows someone new, the bot sends a rich Discord alert containing:
- ✅ Who followed whom (with clickable X profile links)
- ✅ The new account's follower count
- ✅ The new account's bio
- ✅ The new account's project category (AI-powered — see below)
- ✅ The new account's profile picture thumbnail
- ✅ A precise timestamp in your timezone
On top of the per-follow alerts, the bot can post an hourly summary that groups every new follow by project category (AI, Layer 2, DeFi, NFT, …) and shows how many of your watched accounts followed each target — so you instantly see what the crowd is piling into.
Common use cases:
| Use Case | Description |
|---|---|
| 🐦 Alpha tracking | See what KOLs and influencers follow early |
| 📊 Project discovery | Catch new projects before they trend |
| 🔍 Due diligence | Monitor competitor or partner follow activity |
| 🎯 Signal detection | Spot accounts followed by multiple watchers |
| Feature | Description |
|---|---|
| Real-Time Discord Alerts | Rich embeds with profile link, bio, followers & avatar |
| AI Categorization | Tags each followed account by project category (AI, Layer 2, DeFi, NFT…) via OpenRouter LLM + keyword fallback |
| Hourly Summary | Posts a periodic digest grouped by category, counting how many watchers followed each target |
| Optional Dynamic Query IDs | Built-in GraphQL query IDs work out of the box; opt in to dynamic_query_ids to auto-pull the latest IDs + feature flags from x.com if X ever rotates them out |
| Smart Category Cache | Caches each account's category (7-day TTL) to conserve OpenRouter free-tier quota |
| Cookie Pool Rotation | Use multiple X auth cookies with round-robin rotation to reduce rate limits |
| Auto Dedup | Duplicate accounts in your watch list are removed automatically |
| Skip Bad Users | Suspended / deactivated accounts are skipped gracefully |
| Warmup Baseline | Existing follows are recorded first — no notification spam on startup |
| Rate-Limit Handling | Automatically waits and rotates cookies when X rate-limits you |
| Graceful Shutdown | Ctrl + C saves state cleanly before exiting |
| Config Validation | Catches mistakes at startup, not mid-run |
| Structured Logging | Timestamped logs with levels (debug / info / warn / error) |
| Ultra Lightweight | Single ~6 MB binary, ~14 MB RAM, zero runtime dependencies |
Before installing, make sure you have:
- A computer or server running Linux, macOS, or Windows.
- An X / Twitter account (use a spare/alt account — see the warning in Step 5).
- A Discord server where you have permission to create a webhook.
- About 10 minutes ⏱️.
💡 New to the command line? Don't worry. Just copy and paste each command below, one at a time, and press Enter. The guide explains every step.
This guide is written for beginners. Follow each step in order.
X-Tracker-Bot is built with Go (version 1.24 or newer). If you don't have Go installed yet, install it:
Linux (Ubuntu / Debian):
sudo apt update && sudo apt install -y golang-go gitmacOS (with Homebrew):
brew install go gitWindows: Download and run the installer from https://go.dev/dl/, then install Git for Windows.
Verify the installation:
go versionYou should see something like go version go1.24.3. ✅
Clone the repository to your computer:
git clone https://github.com/DezXBT/X-Tracker-Bot.git
cd X-Tracker-Bot📦 Prefer not to build? Grab a ready-made binary from the Releases page and skip to Step 4.
Compile the bot into a single executable file:
go build -ldflags="-s -w" -o x-tracker .This creates an x-tracker file (about 6 MB) in the folder. The -ldflags="-s -w" flags strip debug info to keep it small.
Copy the example config to create your own:
cp config.example.yaml config.yamlYou'll edit config.yaml in the next steps to add your X cookies and Discord webhook.
The bot logs into X using two browser cookies: auth_token and ct0.
- Log in to x.com in your web browser.
- Open Developer Tools by pressing
F12(or right-click → Inspect). - Go to the Application tab → Cookies →
https://x.com. - Find and copy these two values:
auth_token— a long hex stringct0— a long hex string
- Open
config.yamland paste them in:
twitter:
cookies:
- { auth_token: "PASTE_YOUR_AUTH_TOKEN_HERE", ct0: "PASTE_YOUR_CT0_HERE" }💡 Tip: the
{ ... }flow style keeps each cookie on one line, so you can't get the indentation wrong.
⚠️ Security warning: These cookies grant full access to the X account. Use a dedicated alt account, never your main account. Never share your config file or commit it to GitHub.
Optional but recommended — add multiple cookies to spread requests across accounts and avoid rate limits (one per line):
twitter:
cookies:
- { auth_token: "account1_token", ct0: "account1_ct0" }
- { auth_token: "account2_token", ct0: "account2_ct0" }
- { auth_token: "account3_token", ct0: "account3_ct0" }
- { auth_token: "account4_token", ct0: "account4_ct0" }✅ Validate before running to catch typos:
python3 -c "import yaml; yaml.safe_load(open('config.yaml')); print('YAML OK')"
- In Discord, open the channel where you want alerts.
- Click the ⚙️ Edit Channel → Integrations → Webhooks.
- Click New Webhook, give it a name (e.g. X-Tracker), then Copy Webhook URL.
- Paste it into
config.yaml:
discord:
raw_webhooks:
- "https://discord.com/api/webhooks/YOUR_WEBHOOK_URL_HERE"Open the twitter.txt file and add the X accounts you want to monitor — one per line. All of these formats work:
https://x.com/elonmusk
@SkyAAmen
0xtunglee
https://twitter.com/handle
- Blank lines and lines starting with
#are ignored. - Duplicate accounts are removed automatically.
Quick way to add one from the command line:
echo "https://x.com/elonmusk" >> twitter.txtYou're ready! Start the bot:
./x-trackerOn the first run, the bot records everyone your watched accounts already follow (the "warmup baseline") — so you won't get spammed. After that, it checks every 10 minutes (configurable) and alerts you on new follows only. 🎉
Press Ctrl + C to stop the bot — it saves its state cleanly before exiting.
💡 This step is optional. Skip it and the bot works exactly like the classic version (raw alerts only). Turn it on to label every follow by project category and get an hourly digest.
The bot can categorize each followed account (AI, Layer 2, DeFi, NFT, Meme, KOL…) using a Large Language Model via OpenRouter — which offers free-tier models. It judges from the bio + recent tweets (not the username), and uses KOL for individual people (influencers/alpha callers) rather than forcing them into a project category. Here's how to set it up:
1. Get one (or more) OpenRouter API keys
- Sign up at openrouter.ai.
- Go to Keys → Create Key and copy it (starts with
sk-or-v1-...). - (Recommended) Create several keys — the bot rotates them round-robin to spread the free-tier quota.
2. Put your keys in llm.txt (one key per line). This keeps secrets out of config.yaml:
cp llm.example.txt llm.txtThen edit llm.txt:
sk-or-v1-your_first_key
sk-or-v1-your_second_key
# lines starting with # are ignored
🔒
llm.txtis git-ignored, just likeconfig.yaml. Never commit or share it.
3. Add a summary webhook (a second Discord webhook, see Step 6) — ideally a separate channel so digests don't clutter your real-time alerts.
4. Fill in the categorization and summary settings in config.yaml (note: keys live in llm.txt, not here):
discord:
raw_webhooks:
- "https://discord.com/api/webhooks/REALTIME_ALERTS"
summary_webhook: "https://discord.com/api/webhooks/HOURLY_SUMMARY" # leave empty to disable summaries
summary_interval: 1h # how often to post the digest
summary_dedup_ttl: 720h # report each project once; re-eligible after this long (30d)
summary_max_followers_enabled: true # on by default — only show targets with followers <= max
summary_max_followers: 1000 # the max (used only when the filter is enabled)
summary_show_bio: true # 📝 on by default — show each account's latest bio
categorization:
enabled: true
use_tweets: true # also read recent tweets as a signal (1 extra API call per new account)
tweet_count: 8 # original tweets to read (retweets skipped)
cache_ttl: 168h # remember a category for 7 days (saves quota)
keys_file: llm.txt # where OpenRouter API keys are read from
categories: # base taxonomy — the LLM may add new ones when nothing fits
- AI
- Layer 1
- Layer 2
- DeFi
- NFT
- Gaming
- Meme
- DePIN
- RWA
- Infra
- Social
- KOL # an individual person (influencer/alpha caller), not a project
- Trading
- Other
openrouter:
api_keys: [] # optional; prefer llm.txt. Merged with keys from the file
models: # free-tier models, tried in order until one works
- "openai/gpt-oss-120b:free"
- "z-ai/glm-4.5-air:free"
- "openai/gpt-oss-20b:free"
# Free model names change often — if you get 404s, refresh from
# https://openrouter.ai/models?max_price=0
# (Optional) Frontrun enrichment for the summary — off by default
frontrun:
enabled: false # true = add extra signals to each summary line
base_url: "https://frontrun.network"
tokens: # session token pool, rotated round-robin per request
- "SESSION_TOKEN_1"
- "SESSION_TOKEN_2"
token: "" # optional single token, merged into the pool
token_file: frontrun.txt # optional: one token per line (git-ignored)
client_version: "" # headers the Frontrun web app sends
client_language: "en"
show_username_change: true # ✏️ ex @oldname when the account ever renamed
show_smart_followers: true # 🧠 N smart followers
cache_ttl: 168h # cache an enrichment per handle for 7 daysWhen enabled, each account in the summary gains optional markers — e.g.
`2×` [@handle](…) · 👥 1.2K · 🧠 12 · ✏️ ex @oldname — where 🧠 is the
smart-followers count and ✏️ flags a past username change (with the previous handle).
Multiple tokens are rotated round-robin, and a throttled/expired token retries
on the next one. The feature only touches the summary; raw alerts are unchanged, and
when enabled: false no Frontrun API calls are made at all.
How it degrades gracefully:
| Situation | What happens |
|---|---|
| No OpenRouter keys | Falls back to keyword matching (still tags obvious categories) |
| All LLM models fail / quota hit | Falls back to keyword matching, then Uncategorized |
summary_webhook empty |
Summaries are disabled; raw alerts still work |
enabled: false |
Categorization off entirely; behaves like the classic bot |
⚠️ Free-tier note: OpenRouter's free models have daily limits, and the available model names change over time. List a few models as fallbacks, add multiple keys, and keepcache_ttlhigh so the same account isn't re-queried. If a model 404s, the bot just tries the next one.
All settings live in config.yaml:
# X / Twitter authentication (flow style { } keeps indentation foolproof)
twitter:
cookies:
- { auth_token: "xxx", ct0: "yyy" }
# Path to the file listing accounts to watch
watch_file: twitter.txt
# Tracking behavior
tracking:
track_all_follows: true # true = alert on ALL new follows
# false = only alert when a watcher follows
# an account also listed in twitter.txt
poll_interval: 10m # How often to scan (Go duration: 30s, 10m, 1h)
page_size: 10 # Users fetched per API page
max_pages: 2 # Max pages per watcher per scan
page_delay: 500ms # Delay between API pages
dynamic_query_ids: false # Pull latest GraphQL IDs from x.com (only if built-ins break)
# Discord webhook(s)
discord:
raw_webhooks: # real-time, per-follow alerts
- "https://discord.com/api/webhooks/..."
summary_webhook: "..." # (optional) hourly category digest — empty = off
summary_interval: 1h # how often to post the digest
summary_dedup_ttl: 720h # report each project only once (re-eligible after 30d)
summary_max_followers_enabled: true # on by default — only show targets with followers <= max
summary_max_followers: 1000 # the max (used only when the filter is enabled)
summary_show_bio: true # 📝 on by default — show each account's latest bio
# (Optional) AI categorization — see Step 9 for the full walkthrough
categorization:
enabled: true # false = disable (raw alerts still work)
use_tweets: true # read recent tweets as an extra signal
tweet_count: 8 # how many recent original tweets to fetch (retweets skipped)
cache_ttl: 168h # how long a category is cached (7 days)
keys_file: llm.txt # OpenRouter API keys, one per line (preferred over inline)
categories: [AI, Layer 2, DeFi, NFT, Meme, KOL, Trading, Other, ...] # taxonomy (LLM may extend)
openrouter:
api_keys: [] # optional inline keys; merged with llm.txt. None = keyword-only
models: ["openai/gpt-oss-120b:free", "z-ai/glm-4.5-air:free", "..."] # tried in order
# (Optional) Frontrun summary enrichment — off by default
frontrun:
enabled: false # true = add 🧠 smart-followers + ✏️ username-change markers
base_url: "https://frontrun.network"
tokens: ["SESSION_TOKEN_1", "SESSION_TOKEN_2"] # round-robin pool
token_file: frontrun.txt # optional: one token per line (git-ignored)
client_language: "en"
cache_ttl: 168h # cache enrichment per handle (7 days)
# Logging
logging:
timezone: Asia/Jakarta # Timezone for log & alert timestamps
level: info # debug | info | warn | error| Mode | track_all_follows |
Behavior |
|---|---|---|
| Full | true |
Alert on every new follow from your watched accounts |
| Targeted | false |
Alert only when a watcher follows an account that's also in twitter.txt |
To keep the bot running continuously on a server, pick one of these options.
pm2 start ./x-tracker --name x-tracker
pm2 save
pm2 startupsudo tee /etc/systemd/system/x-tracker.service << 'EOF'
[Unit]
Description=X-Tracker-Bot
After=network.target
[Service]
Type=simple
WorkingDirectory=/path/to/X-Tracker-Bot
ExecStart=/path/to/X-Tracker-Bot/x-tracker
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable x-tracker
sudo systemctl start x-trackerscreen -S x-tracker
./x-tracker
# Press Ctrl+A then D to detach and leave it running┌──────────────┐ ┌──────────────────────┐ ┌──────────────────┐
│ twitter.txt │────▶│ X-Tracker-Bot │────▶│ Discord (raw) │
│ (watch list)│ │ │ │ per-follow alert│
└──────────────┘ │ 0. Refresh query IDs│ └──────────────────┘
│ 1. Warmup baseline │
┌──────────────┐ │ 2. Scan follows │ ┌──────────────────┐
│ X (Twitter) │◀───▶│ 3. Detect new │ │ Discord (summary)│
│ GraphQL API │ │ 4. Categorize (LLM) │────▶│ hourly digest │
└──────┬───────┘ │ 5. Alert + log │ └──────────────────┘
│ │ 6. Save state │ ┌──────────────────┐
┌──────▼───────┐ └──────────┬───────────┘ │ state.json │
│ OpenRouter │◀───────────────┘ │ events.jsonl │
│ (LLM, free) │ └──────────────────┘
└──────────────┘
Startup
- Query IDs — Uses proven built-in GraphQL query IDs. If
dynamic_query_ids: true, it instead pulls the latest IDs + required feature flags from x.com's JS bundle at startup (use only if X rotates the built-ins out).
Main loop (every poll_interval)
- Warmup — On first run, fetches all current follows as a baseline (no spam).
- Scan — Fetches the latest follows for each watcher (rotating the cookie pool).
- Detect — Compares against the baseline to find new follows.
- Categorize — On a cache miss, reads the target's name/bio (+ recent tweets) and asks the OpenRouter LLM for a category; result is cached for
cache_ttl. Falls back to keyword matching when no LLM is available. - Alert + log — Sends a Discord embed (with category) and appends the follow to
events.jsonl. - Save — Persists state to the
state/directory.
Summary loop (every summary_interval, runs in parallel)
- Reads the last interval's events from
events.jsonl, groups them by category, counts distinct watchers per target, and posts a digest tosummary_webhook. - De-duplicates across summaries: a project that already appeared in a previous summary is skipped, so each project is reported only once (until
summary_dedup_ttlelapses). If an interval has no new projects, no digest is sent. - Follower filter (on by default): targets with more than
summary_max_followersfollowers (default 1,000) are left out of the digest, keeping it focused on smaller/early accounts. Setsummary_max_followers_enabled: falseto show every target. Raw alerts are unaffected, and targets whose follower count is unknown are kept. - Frontrun enrichment (optional, off by default): when
frontrun.enabledistrue, each summary line also shows a smart-followers count (🧠 N) and a username-change marker (✏️ ex @oldname). Results are cached per handle (frontrun.cache_ttl), and the session-token pool is rotated round-robin across requests. No Frontrun calls happen while it's disabled.
| File | Purpose |
|---|---|
state/state.json |
Baseline following list + already-sent alert pairs + category cache |
state/events.jsonl |
Append-only log of all detected follows (used to build the hourly summary) |
🔄 Want to reset? Delete the
state/folder. The bot will re-warmup on the next start.
| Problem | Solution |
|---|---|
config invalid: no twitter cookies configured |
Fill in auth_token and ct0 in config.yaml |
unauthorized (401) |
Your X cookies expired — log in again and grab fresh ones |
rate limited (429) |
Add more cookies to the pool, or increase poll_interval |
| No alerts appearing | Double-check the webhook URL and that twitter.txt has accounts |
watch_file not found |
Make sure twitter.txt exists in the same folder as the binary |
| Bot sends old follows on restart | Delete the state/ folder and restart |
command not found: go |
Go isn't installed — revisit Step 1 |
Everything shows as Uncategorized |
No key in llm.txt, or all models failed/hit quota — add keys/models (see Step 9) |
openrouter ... failed: HTTP 404 |
That free model name is gone — update the models list with a current one |
| No hourly summary appears | Set summary_webhook; the digest only sends when there are new projects (ones not already summarized) in the interval |
Scans fail with GraphQL error: ... after X changed something |
The built-in query IDs were rotated out — set dynamic_query_ids: true and restart to pull the latest IDs + feature flags from x.com |
bundle refresh failed (only if dynamic_query_ids: true) |
Couldn't reach x.com; the bot falls back to built-in IDs. Check outbound network, or set dynamic_query_ids: false |
What is X-Tracker-Bot used for? It tracks who specific X (Twitter) accounts follow and sends a real-time Discord alert whenever they follow someone new — ideal for alpha hunting, KOL tracking, and project discovery.
Is X-Tracker-Bot free? Yes. It's free and open-source under the MIT license.
Do I need a Twitter / X API key?
No. The bot authenticates using your browser cookies (auth_token and ct0) instead of the official paid API.
Is it safe to use my X account?
Use a dedicated alt account, never your main. The cookies grant full account access, so keep your config.yaml private and never commit it to a public repo.
How often does it check for new follows?
By default every 10 minutes. You can change this with the poll_interval setting (e.g. 30s, 5m, 1h).
Will I get spammed with notifications when I first run it? No. The first run is a "warmup" that records existing follows silently. You'll only be alerted about follows that happen after startup.
Can I track multiple accounts at once?
Yes. Add as many accounts as you like to twitter.txt, one per line.
Can I send alerts to multiple Discord channels?
Yes. Add multiple webhook URLs under discord.raw_webhooks.
Do I have to use the AI categorization?
No. It's optional. Leave categorization.openrouter.api_keys empty (or set enabled: false) and the bot runs like the classic version. With no LLM it still does basic keyword categorization.
Does the AI categorization cost money?
It can be free. OpenRouter offers free-tier models (the ones ending in :free). The bot caches each account's category for 7 days and rotates multiple keys to stay within free limits. You can also add paid models if you prefer.
Does fetching tweets use extra X requests?
Yes — when use_tweets: true, each newly seen account costs one extra UserTweets call (drawn from the same cookie pool as the tracker). It only happens on a cache miss. Set use_tweets: false to categorize from name + bio only.
Why does a project only show up in the summary once?
By design — to keep the summary channel readable, each project is reported a single time. Once it's in a digest it's excluded from later ones until summary_dedup_ttl (default 30 days) passes, after which renewed interest can surface it again. The real-time raw alerts are unaffected; they still fire on every new follow.
The bot stopped finding follows after X updated — what do I do?
The built-in query IDs are proven to work. If X rotates them out and scans start failing, set dynamic_query_ids: true in config.yaml and restart — the bot will then pull the latest IDs and feature flags from x.com automatically.
What operating systems does it support? Linux, macOS, and Windows. It's a single self-contained binary with no runtime dependencies.
How do I avoid getting rate-limited by X?
Add multiple cookie pairs (cookie pool) for round-robin rotation, and/or increase the poll_interval.
# Requires Go 1.24+
git clone https://github.com/DezXBT/X-Tracker-Bot.git
cd X-Tracker-Bot
go build -ldflags="-s -w" -o x-tracker .Cross-compile for other platforms:
# Linux ARM64 (e.g. Raspberry Pi, ARM VPS)
GOOS=linux GOARCH=arm64 go build -ldflags="-s -w" -o x-tracker-linux-arm64 .
# macOS (Apple Silicon)
GOOS=darwin GOARCH=arm64 go build -ldflags="-s -w" -o x-tracker-macos .
# Windows
GOOS=windows GOARCH=amd64 go build -ldflags="-s -w" -o x-tracker.exe .- Language: Go (single static binary, no runtime dependencies)
- API: X / Twitter internal GraphQL API (cookie-based authentication, optional dynamic query IDs)
- AI: OpenRouter LLM for project categorization (free-tier capable, multi-key rotation) with keyword fallback
- Output: Discord webhooks (rich embeds + hourly category summary)
- State: JSON file persistence (baseline, dedup pairs, category cache)
- Config: YAML with startup validation
Released under the MIT License. Free to use, modify, and distribute.
x tracker, twitter follow tracker, twitter follow alert, x follow notification bot, discord webhook notifier, kol tracking bot, alpha tracker, crypto twitter tracker, x follow monitor, twitter monitoring tool, follow tracking bot, twitter bot, x bot, follow notification, early tracking, twitter follow discord, x follow discord, crypto twitter monitor, kol follow alert, go twitter bot, self-hosted twitter tracker