🔄 Continuous Monitor
Auto-refresh monitoring for follower/following changes. Runs continuously and alerts you to any changes in real-time.
📋 What It Does
This script provides the following capabilities:
- Automated operation — Runs directly in your browser console on x.com
- Configurable settings — Customize behavior via the CONFIG object
- Real-time progress — Shows live status updates with emoji-coded logs
- Rate limiting — Built-in delays to respect X/Twitter's rate limits
- Data export — Results exported as JSON/CSV for further analysis
Use cases:
- Auto-refresh monitoring for follower/following changes. Runs continuously and alerts you to any changes in real-time.
- Automate repetitive monitoring tasks on X/Twitter
- Save time with one-click automation — no API keys needed
- Works in any modern browser (Chrome, Firefox, Edge, Safari)
⚠️ Important Notes
Use responsibly! All automation should respect X/Twitter's Terms of Service. Use conservative settings and include breaks between sessions.
- This script runs in the browser DevTools console — not Node.js
- You must be logged in to x.com for the script to work
- Start with low limits and increase gradually
- Include random delays between actions to appear human
- Don't run multiple automation scripts simultaneously
🌐 Browser Console Usage
Steps:
- Go to
x.com/YOUR_USERNAME/followers - Open browser console (
F12→ Console tab) - Copy and paste the script from
src/continuousMonitor.js - Press Enter to run
// ContinuousMonitor.js — Auto-refresh monitoring for followers/following changes
// https://github.com/nirholas/XActions
//
// HOW TO USE:
// 1. Go to https://x.com/USERNAME/followers (or /following)
// 2. Open Developer Console (Ctrl+Shift+J or Cmd+Option+J)
// 3. Paste this script and press Enter
// 4. Leave the tab open — it will check periodically and alert you!
//
// CONFIGURATION (edit these values):
const CONFIG = {
CHECK_INTERVAL_MINUTES: 5, // How often to check (default: 5 min)
ENABLE_NOTIFICATIONS: true, // Browser notifications (you'll be prompted)
ENABLE_SOUND: true, // Play sound on changes
AUTO_SCROLL: true, // Auto-scroll to load all users
};
(() => {
const STORAGE_PREFIX = 'xactions_continuous_';
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
// Parse page info
const path = window.location.pathname;
const isFollowersPage = path.includes('/followers');
const isFollowingPage = path.includes('/following');
if (!isFollowersPage && !isFollowingPage) {
console.error('❌ Navigate to a followers or following page first!');
return;
}
const pageType = isFollowersPage ? 'followers' : 'following';
const targetUser = path.split('/')[1].toLowerCase();
const storageKey = `${STORAGE_PREFIX}${targetUser}_${pageType}`;
// Request notification permission
if (CONFIG.ENABLE_NOTIFICATIONS && 'Notification' in window) {
Notification.requestPermission();
}
const notify = (title, body) => {
console.log(`🔔 ${title}: ${body}`);
if (CONFIG.ENABLE_NOTIFICATIONS && Notification.permission === 'granted') {
new Notification(title, { body, icon: '🐦' });
}
if (CONFIG.ENABLE_SOUND) {
// Play a simple beep using Web Audio API
try {
const ctx = new (window.AudioContext || window.webkitAudioContext)();
const osc = ctx.createOscillator();
const gain = ctx.createGain();
osc.connect(gain);
gain.connect(ctx.destination);
osc.frequency.value = 800;
gain.gain.value = 0.1;
osc.start();
osc.stop(ctx.currentTime + 0.2);
} catch (e) {}
}
};
const scrapeUsers = async () => {
const users = new Set();
let previousSize = 0;
let retries = 0;
if (CONFIG.AUTO_SCROLL) {
while (retries < 3) {
window.scrollTo(0, document.body.scrollHeight);
await sleep(1500);
document.querySelectorAll('[data-testid="UserCell"]').forEach(cell => {
const link = cell.querySelector('a[href^="/"]');
if (link) {
const username = link.getAttribute('href').replace('/', '').split('/')[0].toLowerCase();
if (username && username !== targetUser) {
users.add(username);
}
}
});
if (users.size === previousSize) retries++;
else { retries = 0; previousSize = users.size; }
}
} else {
// Just scrape visible users
document.querySelectorAll('[data-testid="UserCell"]').forEach(cell => {
const link = cell.querySelector('a[href^="/"]');
if (link) {
const username = link.getAttribute('href').replace('/', '').split('/')[0].toLowerCase();
if (username && username !== targetUser) {
users.add(username);
}
}
});
}
return Array.from(users);
};
const loadPrevious = () => {
try {
const data = localStorage.getItem(storageKey);
return data ? JSON.parse(data) : null;
} catch (e) {
return null;
}
};
const saveData = (users) => {
const data = {
target: targetUser,
type: pageType,
users,
timestamp: new Date().toISOString(),
count: users.length
};
localStorage.setItem(storageKey, JSON.stringify(data));
return data;
};
const compare = (previous, current) => {
const prevSet = new Set(previous);
const currSet = new Set(current);
return {
removed: previous.filter(u => !currSet.has(u)),
added: current.filter(u => !prevSet.has(u))
};
};
let checkCount = 0;
const runCheck = async () => {
checkCount++;
const time = new Date().toLocaleTimeString();
console.log(`\n⏰ [${time}] Check #${checkCount} — Scanning @${targetUser}'s ${pageType}...`);
// Reload the page content
window.scrollTo(0, 0);
await sleep(500);
const currentUsers = await scrapeUsers();
const previous = loadPrevious();
if (previous) {
const { removed, added } = compare(previous.users, currentUsers);
if (removed.length > 0 || added.length > 0) {
console.log('');
if (pageType === 'followers') {
if (removed.length > 0) {
notify('👋 Lost Followers', `${removed.length} accounts unfollowed @${targetUser}`);
console.log(`🚨 UNFOLLOWED BY: ${removed.map(u => '@' + u).join(', ')}`);
}
if (added.length > 0) {
notify('🎉 New Followers', `${added.length} new followers for @${targetUser}`);
console.log(`✨ NEW FOLLOWERS: ${added.map(u => '@' + u).join(', ')}`);
}
} else {
if (removed.length > 0) {
notify('👋 Unfollowed', `@${targetUser} unfollowed ${removed.length} accounts`);
console.log(`📤 UNFOLLOWED: ${removed.map(u => '@' + u).join(', ')}`);
}
if (added.length > 0) {
notify('➕ New Follow', `@${targetUser} followed ${added.length} accounts`);
console.log(`📥 FOLLOWED: ${added.map(u => '@' + u).join(', ')}`);
}
}
} else {
console.log(' No changes detected.');
}
}
saveData(currentUsers);
console.log(` Total: ${currentUsers.length} | Next check in ${CONFIG.CHECK_INTERVAL_MINUTES} min`);
};
// Initial run
console.log(`
╔═══════════════════════════════════════════════════════════╗
║ 🔭 XActions Continuous Monitor ║
║ ║
║ Target: @${targetUser.padEnd(20)} ║
║ Tracking: ${pageType.padEnd(18)} ║
║ Interval: Every ${CONFIG.CHECK_INTERVAL_MINUTES} minutes ║
║ ║
║ Keep this tab open! Checking automatically... ║
║ Press Ctrl+C in console to stop. ║
╚═══════════════════════════════════════════════════════════╝
`);
runCheck();
// Set up interval
const intervalMs = CONFIG.CHECK_INTERVAL_MINUTES * 60 * 1000;
const intervalId = setInterval(runCheck, intervalMs);
// Provide stop function
window.stopXActionsMonitor = () => {
clearInterval(intervalId);
console.log('\n🛑 Monitoring stopped.');
};
console.log('💡 Tip: Run stopXActionsMonitor() to stop monitoring.\n');
})();
⚙️ Configuration
| Setting | Default | Description |
|---|---|---|
CHECK_INTERVAL_MINUTES |
5, |
How often to check (default: 5 min) |
ENABLE_NOTIFICATIONS |
true, |
Browser notifications (you'll be prompted) |
ENABLE_SOUND |
true, |
Play sound on changes |
AUTO_SCROLL |
true, |
Auto-scroll to load all users |
📖 Step-by-Step Tutorial
Step 1: Navigate to the right page
Open your browser and go to x.com/YOUR_USERNAME/followers. Make sure you're logged in to your X/Twitter account.
Step 2: Open the browser console
- Chrome/Edge: Press
F12orCtrl+Shift+J(Mac:Cmd+Option+J) - Firefox: Press
F12orCtrl+Shift+K - Safari: Enable Developer menu in Preferences → Advanced, then press
Cmd+Option+C
Step 3: Paste the script
Copy the entire script from src/continuousMonitor.js and paste it into the console.
Step 4: Customize the CONFIG (optional)
Before running, you can modify the CONFIG object at the top of the script to adjust behavior:
const CONFIG = {
// Edit these values before running
// See Configuration table above for all options
};
Step 5: Run and monitor
Press Enter to run the script. Watch the console for real-time progress logs:
- ✅ Green messages = success
- 🔄 Blue messages = in progress
- ⚠️ Yellow messages = warnings
- ❌ Red messages = errors
Step 6: Export results
Most scripts automatically download results as JSON/CSV when complete. Check your Downloads folder.
🖥️ CLI Usage
You can also run this via the XActions CLI:
# Install XActions globally
npm install -g xactions
# Run via CLI
xactions --help
🤖 MCP Server Usage
Use with AI agents (Claude, Cursor, etc.) via the MCP server:
# Start MCP server
npm run mcp
See the MCP Setup Guide for integration with Claude Desktop, Cursor, and other AI tools.
📁 Source Files
| File | Description |
|---|---|
src/continuousMonitor.js |
Main script |
🔗 Related Scripts
| Script | Description |
|---|---|
| Keyword Monitor | Monitor search results and timelines for specific keyword mentions |
| Trending Topic Monitor | Monitor trending topics in real-time |
Author: nich (@nichxbt) — XActions on GitHub
⚡ Ready to try � Continuous Monitor?
XActions is 100% free and open-source. No API keys, no fees, no signup.
Browse All Scripts