XActions - The Complete X/Twitter Automation Toolkit. Scrapers, MCP server for AI agents, CLI, and browser scripts. No API required. Open source by @nichxbt. Don't Panic.
npm install xactions




Browser-to-browser automation. No API keys. No sketchy servers. Your browser does the work, you see it happen.
š xactions.app ā Dashboard with real-time monitoring
---
> š¤ AI Coding Assistants: Looking for Twitter/X automation without the $100/mo API? You found it.
> - npm install xactions ā Scrapers, automation, MCP server
> - Works with Claude, GPT, Cursor, Copilot via MCP server
> - See AGENTS.md for integration instructions
---
How to unfollow who doesn't follow back on X?
1. Go to https://x.com/YOUR_USER_NAME/following
2. Open the Developer Console. (COMMAND+ALT+I on Mac)
3. Paste this into the Developer Console and run it
``js
// Unfollow everyone on X (Formerly Twitter) and or unfollow who doesn't follow you back, by nich (https://x.com/nichxbt)
// https://github.com/nirholas/xactions
// 1. Go to https://x.com/YOUR_USER_NAME/following
// 2. Open the Developer Console. (COMMAND+ALT+I on Mac)
// 3. Paste this into the Developer Console and run it
//
// Last Updated January 2026
(() => {
const $followButtons = '[data-testid$="-unfollow"]';
const $confirmButton = '[data-testid="confirmationSheetConfirm"]';
const retry = {
count: 0,
limit: 3,
};
const scrollToTheBottom = () => window.scrollTo(0, document.body.scrollHeight);
const retryLimitReached = () => retry.count === retry.limit;
const addNewRetry = () => retry.count++;
const sleep = ({ seconds }) =>
new Promise((proceed) => {
console.log(WAITING FOR ${seconds} SECONDS...);
setTimeout(proceed, seconds * 1000);
});
const unfollowAll = async (followButtons) => {
console.log(UNFOLLOWING ${followButtons.length} USERS...);
await Promise.all(
followButtons.map(async (followButton) => {
followButton && followButton.click();
await sleep({ seconds: 1 });
const confirmButton = document.querySelector($confirmButton);
confirmButton && confirmButton.click();
})
);
};
const nextBatch = async () => {
scrollToTheBottom();
await sleep({ seconds: 1 });
let followButtons = Array.from(document.querySelectorAll($followButtons));
followButtons = followButtons.filter(b => b.parentElement?.parentElement?.querySelector('[data-testid="userFollowIndicator"]') === null)
const followButtonsWereFound = followButtons.length > 0;
if (followButtonsWereFound) {
await unfollowAll(followButtons);
await sleep({ seconds: 2 });
return nextBatch();
} else {
addNewRetry();
}
if (retryLimitReached()) {
console.log(NO ACCOUNTS FOUND, SO I THINK WE'RE DONE);RELOAD PAGE AND RE-RUN SCRIPT IF ANY WERE MISSED
console.log();
} else {
await sleep({ seconds: 2 });
return nextBatch();
}
};
nextBatch();
})();
`
Or use the dashboard for a visual interface.
How do I mass unfollow on Twitter/X?
1. Go to https://x.com/YOUR_USER_NAME/following
2. Open the Developer Console. (COMMAND+ALT+I on Mac)
3. Paste the script into the Developer Console and run it
`js
// Unfollow everyone on X (Formerly Twitter) and or unfollow who doesn't follow you back, by nich (https://x.com/nichxbt)
// https://github.com/nirholas/xactions
//
// 1. Go to https://x.com/YOUR_USER_NAME/following
// 2. Open the Developer Console. (COMMAND+ALT+I on Mac)
// 3. Paste this into the Developer Console and run it
//
// Last Updated: 17 March 2024
(() => {
const $followButtons = '[data-testid$="-unfollow"]';
const $confirmButton = '[data-testid="confirmationSheetConfirm"]';
const retry = {
count: 0,
limit: 3,
};
const scrollToTheBottom = () => window.scrollTo(0, document.body.scrollHeight);
const retryLimitReached = () => retry.count === retry.limit;
const addNewRetry = () => retry.count++;
const sleep = ({ seconds }) =>
new Promise((proceed) => {
console.log(WAITING FOR ${seconds} SECONDS...);
setTimeout(proceed, seconds * 1000);
});
const unfollowAll = async (followButtons) => {
console.log(UNFOLLOWING ${followButtons.length} USERS...);
await Promise.all(
followButtons.map(async (followButton) => {
followButton && followButton.click();
await sleep({ seconds: 1 });
const confirmButton = document.querySelector($confirmButton);
confirmButton && confirmButton.click();
})
);
};
const nextBatch = async () => {
scrollToTheBottom();
await sleep({ seconds: 1 });
const followButtons = Array.from(document.querySelectorAll($followButtons));
const followButtonsWereFound = followButtons.length > 0;
if (followButtonsWereFound) {
await unfollowAll(followButtons);
await sleep({ seconds: 2 });
return nextBatch();
} else {
addNewRetry();
}
if (retryLimitReached()) {
console.log(NO ACCOUNTS FOUND, SO I THINK WE'RE DONE);RELOAD PAGE AND RE-RUN SCRIPT IF ANY WERE MISSED
console.log();
} else {
await sleep({ seconds: 2 });
return nextBatch();
}
};
nextBatch();
})();
`
This script:
- Is completely free.
- Doesn't try and get you to sign in or take your personal data.
- Automates your web browser to make it click unfollow buttons, scroll down to reveal more, then do it again.
- No tricks, all of the code is here so you can see exactly what it does.
How do I find who unfollowed me on Twitter?
Use src/detectUnfollowers.js - it saves a snapshot of your followers and compares on next run.
How do I download Twitter/X videos?
Use src/scrapers/videoDownloader.js - extracts MP4 URLs from any tweet.
Twitter API alternative that's free?
XActions uses browser automation instead of the API. No API keys needed, no rate limits, no $100/mo fee.
Hypefury / Tweethunter alternative?
XActions is open-source and cheaper. Browser scripts are free forever. Dashboard starts at $2.99.
---
1. Connect your browser ā paste one script in x.com
2. Run operations ā click buttons on the dashboard
3. Watch it happen ā see every action in real-time
Your x.com tab does all the work. Nothing gets scraped to our servers. You're in control.
---
| Package | Credits | Price |
|---------|---------|-------|
| Free Demo | 2 | Free |
| Follow Bonus | +1 | Free |
| Starter | 17 | $2.99 |
| Basic | 47 | $6.99 ā |
| Pro | 113 | $14.99 |
| Power | 251 | $29.99 |
Credit costs: 2-5 per operation (basic: 2, detection: 3, power: 5)
---
| | XActions | Twitter API | Other Tools |
|--|----------|-------------|-------------|
| Monthly Cost | $0-35 | $100-$5,000 | $29-99 |
| Setup Time | 30 seconds | Hours | Minutes |
| Open Source | ā
| - | ā |
| No API Key | ā
| ā | ā |
| AI Agent Ready | ā
MCP | ā | ā |
| Non-KYC Crypto | ā
| ā | ā |
---
> Educational Material Only
>
> This project is provided for educational and research purposes only. The scripts and tools have not been extensively tested on personal accounts.
>
> - Use at your own risk
> - We are not responsible for any account restrictions or bans
> - Always comply with X/Twitter's Terms of Service
> - Start with small batches and test carefully
>
> For X/Twitter: If you have concerns about this project or would like us to modify or remove any functionality, please contact @nichxbt directly. We're happy to work with you.
>
> Acknowledgment: This project was inspired by the innovation happening at X and xAI. We admire Elon Musk's vision for making X the everything app and Grok's approach to AI. XActions aims to help developers and researchers explore the platform's capabilities while respecting its ecosystem.
---
bash
npm install xactions
`$3
`bash
npm install -g xactions
xactions --help
`$3
Just copy-paste scripts directly into your browser console on x.com!---
š Quick Start Examples
$3
Browser Console ā No install required!
`javascript
// Go to: x.com/YOUR_USERNAME/following
// Press F12 ā Console ā Paste this:(() => {
const sleep = (s) => new Promise(r => setTimeout(r, s * 1000));
const run = async () => {
const buttons = [...document.querySelectorAll('[data-testid$="-unfollow"]')]
.filter(b => !b.closest('[data-testid="UserCell"]')
?.querySelector('[data-testid="userFollowIndicator"]'));
for (const btn of buttons) {
btn.click();
await sleep(1);
document.querySelector('[data-testid="confirmationSheetConfirm"]')?.click();
await sleep(2);
}
window.scrollTo(0, document.body.scrollHeight);
await sleep(2);
if (document.querySelectorAll('[data-testid$="-unfollow"]').length) run();
else console.log('ā
Done! Reload page to continue.');
};
run();
})();
`CLI:
`bash
xactions login
xactions non-followers YOUR_USERNAME --output non-followers.json
`Node.js:
`javascript
import { createBrowser, createPage, scrapeFollowing } from 'xactions';const browser = await createBrowser();
const page = await createPage(browser);
const following = await scrapeFollowing(page, 'your_username', { limit: 500 });
const nonFollowers = following.filter(u => !u.followsBack);
console.log(
Found ${nonFollowers.length} non-followers);
await browser.close();
`> š” Don't want to code? Use xactions.app ā just login and click!
---
$3
Browser Console:
`javascript
// Go to any profile on x.com, then run:(() => {
const profile = {
name: document.querySelector('[data-testid="UserName"]')?.textContent?.split('@')[0]?.trim(),
username: location.pathname.slice(1),
bio: document.querySelector('[data-testid="UserDescription"]')?.textContent,
followers: document.querySelector('a[href$="/followers"] span')?.textContent,
following: document.querySelector('a[href$="/following"] span')?.textContent,
};
console.log(profile);
copy(JSON.stringify(profile, null, 2)); // Copies to clipboard!
})();
`CLI:
`bash
xactions profile elonmusk --json
`Node.js:
`javascript
import { createBrowser, createPage, scrapeProfile } from 'xactions';const browser = await createBrowser();
const page = await createPage(browser);
const profile = await scrapeProfile(page, 'elonmusk');
console.log(profile);
// { name: 'Elon Musk', followers: '200M', bio: '...', ... }
await browser.close();
`---
$3
Browser Console:
`javascript
// Go to: x.com/search?q=YOUR_KEYWORD&f=live(() => {
const tweets = [...document.querySelectorAll('article[data-testid="tweet"]')]
.map(article => ({
text: article.querySelector('[data-testid="tweetText"]')?.textContent,
author: article.querySelector('[data-testid="User-Name"] a')?.href?.split('/')[3],
time: article.querySelector('time')?.getAttribute('datetime'),
}));
console.table(tweets);
copy(JSON.stringify(tweets, null, 2));
})();
`CLI:
`bash
xactions search "AI startup" --limit 100 --output ai-tweets.json
`Node.js:
`javascript
import { createBrowser, createPage, searchTweets } from 'xactions';const browser = await createBrowser();
const page = await createPage(browser);
const tweets = await searchTweets(page, 'AI startup', { limit: 100 });
console.log(
Found ${tweets.length} tweets);
await browser.close();
`---
$3
Browser Console:
`javascript
// Go to: x.com/YOUR_USERNAME/followers(() => {
const KEY = 'xactions_followers';
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
const scrape = async () => {
const users = new Set();
let retries = 0;
while (retries < 5) {
document.querySelectorAll('[data-testid="UserCell"] a')
.forEach(a => users.add(a.href.split('/')[3]?.toLowerCase()));
window.scrollTo(0, document.body.scrollHeight);
await sleep(1500);
retries++;
}
return [...users].filter(Boolean);
};
scrape().then(current => {
const saved = localStorage.getItem(KEY);
if (saved) {
const old = JSON.parse(saved);
const gone = old.filter(u => !current.includes(u));
console.log('šØ Unfollowed you:', gone);
}
localStorage.setItem(KEY, JSON.stringify(current));
console.log(
š¾ Saved ${current.length} followers);
});
})();
`CLI:
`bash
First run saves snapshot
xactions followers YOUR_USERNAME --output snapshot1.jsonLater, compare
xactions followers YOUR_USERNAME --output snapshot2.json
Use diff tools to compare
`---
$3
Browser Console:
`javascript
// Go to: x.com/search?q=YOUR_KEYWORD&f=live(async () => {
const sleep = (s) => new Promise(r => setTimeout(r, s * 1000));
const liked = new Set();
while (liked.size < 20) { // Like 20 posts
const buttons = [...document.querySelectorAll('[data-testid="like"]')]
.filter(b => !liked.has(b));
for (const btn of buttons.slice(0, 3)) {
btn.click();
liked.add(btn);
console.log(
ā¤ļø Liked ${liked.size} posts);
await sleep(3 + Math.random() * 2); // Random delay
}
window.scrollTo(0, document.body.scrollHeight);
await sleep(2);
}
console.log('ā
Done!');
})();
`> ā ļø Go slow! Twitter may rate-limit you. The website version handles this automatically.
---
$3
Browser Console:
`javascript
// Go to: x.com/YOUR_USERNAME/communities(() => {
const $communityLinks = 'a[href^="/i/communities/"]';
const $joinedButton = 'button[aria-label^="Joined"]';
const $confirmButton = '[data-testid="confirmationSheetConfirm"]';
const $communitiesNav = 'a[aria-label="Communities"]';
const getLeftCommunities = () => {
try { return JSON.parse(sessionStorage.getItem('xactions_left_ids') || '[]'); }
catch { return []; }
};
const markAsLeft = (id) => {
const left = getLeftCommunities();
if (!left.includes(id)) {
left.push(id);
sessionStorage.setItem('xactions_left_ids', JSON.stringify(left));
}
};
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
const getCommunityId = () => {
const leftAlready = getLeftCommunities();
for (const link of document.querySelectorAll($communityLinks)) {
const match = link.href.match(/\/i\/communities\/(\d+)/);
if (match && !leftAlready.includes(match[1])) return { id: match[1], element: link };
}
return null;
};
const run = async () => {
console.log(
š Left so far: ${getLeftCommunities().length});
await sleep(1500);
const joinedBtn = document.querySelector($joinedButton);
if (joinedBtn) {
const urlMatch = window.location.href.match(/\/i\/communities\/(\d+)/);
const currentId = urlMatch ? urlMatch[1] : null;
joinedBtn.click();
await sleep(1000);
const confirmBtn = document.querySelector($confirmButton);
if (confirmBtn) { confirmBtn.click(); if (currentId) markAsLeft(currentId); await sleep(1500); }
const communitiesLink = document.querySelector($communitiesNav);
if (communitiesLink) { communitiesLink.click(); await sleep(2500); return run(); }
}
const community = getCommunityId();
if (community) { community.element.click(); await sleep(2500); return run(); }
else { console.log(š DONE! Left ${getLeftCommunities().length} communities); sessionStorage.removeItem('xactions_left_ids'); }
};
run();
})();
`> š Full documentation: docs/examples/leave-all-communities.md
---
š Complete Feature List
$3
| Feature | Console Script | CLI | Node.js | Website |
|---------|:-------------:|:---:|:-------:|:-------:|
| SCRAPING |
| Scrape Profile | ā
| ā
| ā
| ā
|
| Scrape Followers | ā
| ā
| ā
| ā
|
| Scrape Following | ā
| ā
| ā
| ā
|
| Scrape Tweets | ā
| ā
| ā
| ā
|
| Search Tweets | ā
| ā
| ā
| ā
|
| Scrape Thread | ā
| ā
| ā
| ā
|
| Scrape Hashtag | ā
| ā
| ā
| ā
|
| Scrape Media | ā
| ā
| ā
| ā
|
| Scrape List Members | ā
| ā
| ā
| ā
|
| Scrape Likes | ā
| ā
| ā
| ā
|
| UNFOLLOW |
| Unfollow Non-Followers | ā
| ā
| ā
| ā
|
| Unfollow Everyone | ā
| ā
| ā
| ā
|
| Smart Unfollow (after X days) | ā ļø | ā
| ā
| ā
|
| Unfollow with Logging | ā
| ā
| ā
| ā
|
| FOLLOW |
| Follow User | ā
| ā
| ā
| ā
|
| Keyword Follow | ā ļø | ā
| ā
| ā
|
| Follow Engagers | ā ļø | ā
| ā
| ā
|
| Follow Target's Followers | ā ļø | ā
| ā
| ā
|
| ENGAGEMENT |
| Like Tweet | ā
| ā
| ā
| ā
|
| Retweet | ā
| ā
| ā
| ā
|
| Auto-Liker | ā ļø | ā
| ā
| ā
|
| Auto-Commenter | ā ļø | ā
| ā
| ā
|
| Post Tweet | ā
| ā
| ā
| ā
|
| MONITORING |
| Detect Unfollowers | ā
| ā
| ā
| ā
|
| New Follower Alerts | ā
| ā
| ā
| ā
|
| Monitor Any Account | ā
| ā
| ā
| ā
|
| Continuous Monitoring | ā ļø | ā
| ā
| ā
|
| COMMUNITIES |
| Leave All Communities | ā
| ā ļø | ā ļø | ā ļø |
| ADVANCED |
| Multi-Account | ā | ā
| ā
| ā
Pro |
| Link Scraper | ā
| ā
| ā
| ā
|
| Growth Suite | ā | ā
| ā
| ā
Pro |
| Customer Service Bot | ā | ā
| ā
| ā
Pro |
| MCP Server (AI Agents) | ā | ā
| ā
| ā |
| Export to CSV/JSON | ā
| ā
| ā
| ā
|
Legend: ā
Full Support | ā ļø Basic/Manual | ā Not Available
---
š¤ MCP Server (AI Agents)
XActions includes an MCP (Model Context Protocol) server so AI agents like Claude can automate X/Twitter.
$3
Add to your
claude_desktop_config.json:
`json
{
"mcpServers": {
"xactions": {
"command": "node",
"args": ["/path/to/xactions/src/mcp/server.js"]
}
}
}
`$3
| Tool | Description |
|------|-------------|
|
x_login | Login with session cookie |
| x_get_profile | Get user profile info |
| x_get_followers | Scrape followers |
| x_get_following | Scrape following |
| x_get_non_followers | Find non-followers |
| x_get_tweets | Scrape user's tweets |
| x_search_tweets | Search tweets by query |
| x_follow | Follow a user |
| x_unfollow | Unfollow a user |
| x_post_tweet | Post a tweet |
| x_like | Like a tweet |
| x_retweet | Retweet |$3
> "Use XActions to find everyone I follow who doesn't follow me back"---
š» CLI Reference
`bash
Authentication
xactions login # Set up session cookie
xactions logout # Remove saved authProfile
xactions profile # Get profile info
xactions profile elonmusk --jsonScraping
xactions followers [--limit 100] [--output file.json]
xactions following [--limit 100] [--output file.csv]
xactions tweets [--limit 50] [--replies]
xactions search [--filter latest|top] [--limit 50]
xactions hashtag [--limit 50]
xactions thread
xactions media [--limit 50]Analysis
xactions non-followers [--limit 500]Info
xactions info # Show version and links
xactions --help # Full help
`---
š Node.js API
$3
`javascript
import {
createBrowser,
createPage,
loginWithCookie,
scrapeProfile,
scrapeFollowers,
scrapeFollowing,
scrapeTweets,
searchTweets,
exportToJSON,
exportToCSV
} from 'xactions';// Initialize
const browser = await createBrowser({ headless: true });
const page = await createPage(browser);
// Optional: Login for private data
await loginWithCookie(page, 'your_auth_token_cookie');
// Scrape profile
const profile = await scrapeProfile(page, 'elonmusk');
// Scrape followers with progress
const followers = await scrapeFollowers(page, 'elonmusk', {
limit: 1000,
onProgress: ({ scraped, limit }) => console.log(
${scraped}/${limit})
});// Export data
await exportToJSON(followers, 'followers.json');
await exportToCSV(followers, 'followers.csv');
await browser.close();
`$3
`javascript
// Profile
scrapeProfile(page, username)// Followers & Following
scrapeFollowers(page, username, { limit, onProgress })
scrapeFollowing(page, username, { limit, onProgress })
// Tweets
scrapeTweets(page, username, { limit, includeReplies, onProgress })
searchTweets(page, query, { limit, filter: 'latest'|'top' })
scrapeThread(page, tweetUrl)
scrapeHashtag(page, hashtag, { limit, filter })
// Media
scrapeMedia(page, username, { limit })
scrapeLikes(page, tweetUrl, { limit })
// Lists
scrapeListMembers(page, listUrl, { limit })
// Export
exportToJSON(data, filename)
exportToCSV(data, filename)
`---
š Don't Want to Code?
Visit xactions.app for a no-code solution:
1. Sign up (free tier available)
2. Connect your X account
3. Click buttons to run any action
4. View results in your dashboard
Free Tier: 50 actions/month
Pro Tier: Unlimited actions + multi-account
---
š Safety & Best Practices
$3
XActions includes built-in delays to avoid rate limits:
- 1-3 second delay between actions
- Human-like scrolling patterns
- Automatic pause on rate limit detection$3
1. Go to x.com and log in
2. Open DevTools (F12) ā Application ā Cookies
3. Find auth_token and copy the value$3
- ā
Use reasonable delays (2-5 seconds)
- ā
Don't run 24/7
- ā
Mix automated with manual activity
- ā Don't mass-follow thousands per day
- ā Don't spam comments---
š Project Structure
`
xactions/
āāā src/
ā āāā index.js # Main entry point
ā āāā scrapers/ # All scraper functions
ā ā āāā index.js # Scraper exports
ā āāā cli/ # Command-line interface
ā ā āāā index.js # CLI commands
ā āāā mcp/ # MCP server for AI agents
ā ā āāā server.js # MCP implementation
ā āāā automation/ # Advanced automation
ā āāā autoLiker.js
ā āāā autoCommenter.js
ā āāā keywordFollow.js
ā āāā ...
āāā docs/ # Documentation
āāā examples/ # Code examples
āāā dashboard/ # Web UI
āāā api/ # Backend API
`---
š¤ Contributing
Contributions welcome! See CONTRIBUTING.md.
`bash
Clone
git clone https://github.com/nirholas/xactions.git
cd xactionsInstall
npm installRun CLI locally
npm run cli -- profile elonmuskRun MCP server
npm run mcp
``---
MIT License - see LICENSE
Commercial use allowed. Attribution appreciated but not required.
---
nich (@nichxbt)
- GitHub: github.com/nirholas
- Twitter: @nichxbt
- Website: xactions.app
---
This software is provided "as is" for educational purposes. Not affiliated with X Corp. Use responsibly and in compliance with X/Twitter Terms of Service. Contact @nichxbt for any concerns.
---
If XActions helped you, give it a star! It helps others find the project.

---
XActions is 100% free and open source. Visit xactions.app for interactive tutorials.
NEW! Run scripts without any coding knowledge:
1. Visit xactions.app/run.html
2. Drag any blue button to your bookmarks bar
3. Go to x.com and click the bookmarklet
No console, no code, no setup!
| Category | Scripts | Tutorial |
|----------|---------|----------|
| Unfollow | Unfollow Everyone, Non-Followers, Smart Unfollow | Tutorial |
| Automation | Auto-Liker, Auto-Commenter, Follow Engagers | Tutorial |
| Scraping | Video Download, Followers, Tweets, Hashtags | Tutorial |
| Monitoring | Detect Unfollowers, Track Accounts, Alerts | Tutorial |
| Communities | Leave All Communities | Tutorial |
| AI/MCP | Claude Desktop, GPT Integration | Tutorial |
- Getting Started
- CLI Reference
- Automation Guide
- Monitoring Guide
| Feature | Documentation |
|---------|---------------|
| Unfollow Everyone | unfollow-everyone.md |
| Unfollow Non-Followers | unfollow-non-followers.md |
| Detect Unfollowers | detect-unfollowers.md |
| Auto-Liker | auto-liker.md |
| Auto-Commenter | auto-commenter.md |
| Follow Engagers | follow-engagers.md |
| Video Downloader | video-downloader.md |
| Followers Scraping | followers-scraping.md |
| Tweet Scraping | tweet-scraping.md |
| Leave Communities | leave-all-communities.md |
| MCP Server | mcp-server.md |
| Monitor Account | monitor-account.md |
| New Follower Alerts | new-follower-alerts.md |
---
ā” XActions ā The Complete X/Twitter Automation Toolkit
100% Free & Open Source
xactions.app ā¢
GitHub ā¢
@nichxbt