⚡ Free X/Twitter Automation Features

🎉 XActions is 100% Free & Open Source No accounts, no payments, no limits Star on GitHub ⭐

🧹 Unfollow Tools

👋

Unfollow Everyone

100% Free

Mass unfollow all accounts with one script. Perfect for a fresh start.

📋 View Full Code
Go to: x.com/YOUR_USERNAME/following → Open Console (F12) → Paste & Enter
// Unfollow Everyone - by nichxbt
// Go to: x.com/YOUR_USERNAME/following

(() => {
  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));

    if (followButtons.length > 0) {
      await unfollowAll(followButtons);
      await sleep({ seconds: 2 });
      return nextBatch();
    } else {
      addNewRetry();
    }

    if (retryLimitReached()) {
      console.log(`✅ DONE! Reload page and re-run if any were missed.`);
    } else {
      await sleep({ seconds: 2 });
      return nextBatch();
    }
  };

  console.log('🚀 Starting unfollow everyone...');
  nextBatch();
})();
🔄

Unfollow Non-Followers

100% Free

Remove people who don't follow you back. Clean up your following list.

📋 View Full Code
Go to: x.com/YOUR_USERNAME/following → Open Console (F12) → Paste & Enter
// Unfollow Non-Followers - by nichxbt
// Go to: x.com/YOUR_USERNAME/following

(() => {
  const $followButtons = '[data-testid$="-unfollow"]';
  const $confirmButton = '[data-testid="confirmationSheetConfirm"]';
  const retry = { count: 0, limit: 3 };

  const sleep = ({ seconds }) => new Promise(r => setTimeout(r, seconds * 1000));

  const unfollowAll = async (followButtons) => {
    console.log(`UNFOLLOWING ${followButtons.length} USERS...`);
    for (const btn of followButtons) {
      btn.click();
      await sleep({ seconds: 1 });
      document.querySelector($confirmButton)?.click();
      await sleep({ seconds: 1 });
    }
  };

  const nextBatch = async () => {
    window.scrollTo(0, document.body.scrollHeight);
    await sleep({ seconds: 1 });

    let followButtons = Array.from(document.querySelectorAll($followButtons));
    // Only unfollow those who DON'T follow back (no "Follows you" indicator)
    followButtons = followButtons.filter(b => 
      b.parentElement?.parentElement?.querySelector('[data-testid="userFollowIndicator"]') === null
    );

    if (followButtons.length > 0) {
      await unfollowAll(followButtons);
      await sleep({ seconds: 2 });
      return nextBatch();
    } else if (retry.count < retry.limit) {
      retry.count++;
      await sleep({ seconds: 2 });
      return nextBatch();
    } else {
      console.log(`✅ DONE! Reload and re-run if any were missed.`);
    }
  };

  console.log('🚀 Starting unfollow non-followers...');
  nextBatch();
})();
📝

Smart Unfollow with Logging

100% Free

Unfollow non-followers and download a list of who you unfollowed.

📋 View Full Code
Go to: x.com/YOUR_USERNAME/following → Downloads unfollowed-users.txt when done
// Smart Unfollow with Logging - by nichxbt
// Downloads a list of unfollowed users

(() => {
  const $followButtons = '[data-testid$="-unfollow"]';
  const $confirmButton = '[data-testid="confirmationSheetConfirm"]';
  const unfollowedUsers = [];
  const retry = { count: 0, limit: 5 };

  const sleep = (seconds) => new Promise(r => setTimeout(r, seconds * 1000));

  const unfollowAll = async (followButtons) => {
    for (const button of followButtons) {
      const usernameEl = button.closest('[data-testid="UserCell"]')?.querySelector('[dir="ltr"]');
      const username = usernameEl ? usernameEl.textContent : "Unknown";
      unfollowedUsers.push(username);
      button.click();
      await sleep(2);
      document.querySelector($confirmButton)?.click();
      await sleep(1);
    }
  };

  const createDownload = () => {
    const blob = new Blob([unfollowedUsers.join('\n')], { type: 'text/plain' });
    const a = document.createElement('a');
    a.href = URL.createObjectURL(blob);
    a.download = 'unfollowed-users.txt';
    a.click();
  };

  const nextBatch = async () => {
    window.scrollTo(0, document.body.scrollHeight);
    await sleep(3);
    let followButtons = Array.from(document.querySelectorAll($followButtons));
    followButtons = followButtons.filter(btn => 
      !btn.closest('[data-testid="UserCell"]')?.querySelector('[data-testid="userFollowIndicator"]')
    );

    if (followButtons.length > 0) {
      await unfollowAll(followButtons);
      retry.count = 0;
      await sleep(3);
      nextBatch();
    } else if (retry.count < retry.limit) {
      retry.count++;
      await sleep(3);
      nextBatch();
    } else {
      console.log(`✅ DONE! Unfollowed ${unfollowedUsers.length} users.`);
      if (unfollowedUsers.length > 0) createDownload();
    }
  };

  console.log('🚀 Starting smart unfollow with logging...');
  nextBatch();
})();
🔍

Detect Unfollowers

100% Free

Find out who stopped following you. Run twice to compare.

📋 View Full Code
Go to: x.com/YOUR_USERNAME/followers → Run once to save, run again to compare
// Detect Unfollowers - by nichxbt
// Run once to save, run again later to detect changes

(() => {
  const STORAGE_KEY = 'xactions_my_followers';
  const sleep = (ms) => new Promise(r => setTimeout(r, ms));

  if (!window.location.pathname.includes('/followers')) {
    console.error('❌ Go to: x.com/YOUR_USERNAME/followers');
    return;
  }

  const username = window.location.pathname.match(/^\/([^/]+)\/followers/)?.[1] || 'unknown';

  const scrapeFollowers = async () => {
    const followers = new Set();
    let prevSize = 0, retries = 0;
    console.log('🔍 Scanning followers...');

    while (retries < 5) {
      window.scrollTo(0, document.body.scrollHeight);
      await sleep(1500);
      document.querySelectorAll('[data-testid="UserCell"] a[href^="/"]').forEach(el => {
        const u = el.getAttribute('href').replace('/', '').toLowerCase();
        if (u && !u.includes('/')) followers.add(u);
      });
      console.log(`   Found ${followers.size}...`);
      if (followers.size === prevSize) retries++;
      else { retries = 0; prevSize = followers.size; }
    }
    return Array.from(followers);
  };

  const run = async () => {
    console.log(`\n🐦 Tracking @${username}\n`);
    const current = await scrapeFollowers();
    const prev = JSON.parse(localStorage.getItem(STORAGE_KEY) || 'null');

    if (prev && prev.username === username) {
      const prevSet = new Set(prev.followers);
      const unfollowed = prev.followers.filter(f => !current.includes(f));
      const newFollows = current.filter(f => !prevSet.has(f));

      console.log(`📊 Previous: ${prev.count} | Current: ${current.length}`);
      if (unfollowed.length) {
        console.log(`\n🚨 UNFOLLOWED (${unfollowed.length}):`);
        unfollowed.forEach(u => console.log(`   @${u}`));
      } else console.log('✨ No one unfollowed you!');
      if (newFollows.length) {
        console.log(`\n🎉 NEW (${newFollows.length}):`);
        newFollows.forEach(u => console.log(`   @${u}`));
      }
    } else {
      console.log('📸 First scan! Run again later to detect changes.');
    }

    localStorage.setItem(STORAGE_KEY, JSON.stringify({
      username, followers: current, count: current.length, timestamp: new Date().toISOString()
    }));
    console.log(`\n💾 Saved! Run again to check for changes.\n`);
  };

  run();
})();

🤖 Automation Tools

❤️

Auto Liker

100% Free

Automatically like posts based on keywords.

📋 View Full Code
Go to: x.com/home or any profile → Configure keywords and run
// Auto Liker - by nichxbt
// Configure KEYWORDS array below

(() => {
  const OPTIONS = {
    KEYWORDS: ['web3', 'crypto', 'AI'],  // Edit these!
    MAX_LIKES: 20,
    MIN_DELAY: 2000,
    MAX_DELAY: 5000,
  };

  const sleep = ms => new Promise(r => setTimeout(r, ms));
  const randomDelay = () => sleep(OPTIONS.MIN_DELAY + Math.random() * (OPTIONS.MAX_DELAY - OPTIONS.MIN_DELAY));
  let likeCount = 0;
  const liked = new Set();

  const matchesKeywords = (text) => {
    if (!OPTIONS.KEYWORDS.length) return true;
    return OPTIONS.KEYWORDS.some(kw => text.toLowerCase().includes(kw.toLowerCase()));
  };

  const processTweets = async () => {
    for (const tweet of document.querySelectorAll('[data-testid="tweet"]')) {
      if (likeCount >= OPTIONS.MAX_LIKES) {
        console.log(`✅ Done! Liked ${likeCount} tweets.`);
        return;
      }
      if (liked.has(tweet) || tweet.querySelector('[data-testid="unlike"]')) continue;

      const text = tweet.querySelector('[data-testid="tweetText"]')?.textContent || '';
      if (!matchesKeywords(text)) continue;

      const likeBtn = tweet.querySelector('[data-testid="like"]');
      if (likeBtn) {
        likeBtn.click();
        likeCount++;
        liked.add(tweet);
        console.log(`❤️ Liked #${likeCount}: "${text.substring(0, 50)}..."`);
        await randomDelay();
      }
    }
    window.scrollBy(0, 800);
    await sleep(2000);
    processTweets();
  };

  console.log(`🚀 Auto Liker | Keywords: ${OPTIONS.KEYWORDS.join(', ')}`);
  processTweets();
})();
👥

Follow Engagers

100% Free

Follow users who liked/retweeted a specific post.

📋 View Full Code
Go to: Any tweet → Click likes/retweets → Paste this script
// Follow Engagers - by nichxbt
// Follow users from likes/retweets list

(() => {
  const CONFIG = { MAX_FOLLOWS: 20, DELAY: 3000 };
  const sleep = ms => new Promise(r => setTimeout(r, ms));
  let count = 0;

  const followUsers = async () => {
    for (const cell of document.querySelectorAll('[data-testid="UserCell"]')) {
      if (count >= CONFIG.MAX_FOLLOWS) {
        console.log(`✅ Done! Followed ${count} users.`);
        return;
      }
      const btn = cell.querySelector('[data-testid$="-follow"]');
      if (!btn) continue;

      const username = cell.querySelector('a[href^="/"]')?.getAttribute('href')?.replace('/', '');
      btn.click();
      count++;
      console.log(`✅ Followed @${username} (${count}/${CONFIG.MAX_FOLLOWS})`);
      await sleep(CONFIG.DELAY);
    }
    window.scrollBy(0, 500);
    await sleep(2000);
    followUsers();
  };

  console.log('🚀 Starting Follow Engagers...');
  followUsers();
})();
🔎

Keyword Follow

100% Free

Search for keywords and follow relevant users.

📋 View Full Code
Go to: x.com/search → Search "People" tab → Paste this script
// Keyword Follow - by nichxbt
// Follow users from search results

(() => {
  const CONFIG = { MAX_FOLLOWS: 30, DELAY: 3000, MUST_HAVE_BIO: true };
  const sleep = ms => new Promise(r => setTimeout(r, ms));
  let count = 0;

  const followUsers = async () => {
    for (const cell of document.querySelectorAll('[data-testid="UserCell"]')) {
      if (count >= CONFIG.MAX_FOLLOWS) {
        console.log(`✅ Done! Followed ${count} users.`);
        return;
      }
      const btn = cell.querySelector('[data-testid$="-follow"]');
      if (!btn) continue;

      if (CONFIG.MUST_HAVE_BIO) {
        const bio = cell.querySelector('[data-testid="UserDescription"]');
        if (!bio || !bio.textContent.trim()) continue;
      }

      const username = cell.querySelector('a[href^="/"]')?.getAttribute('href')?.replace('/', '');
      btn.click();
      count++;
      console.log(`✅ Followed @${username} (${count}/${CONFIG.MAX_FOLLOWS})`);
      await sleep(CONFIG.DELAY);
    }
    window.scrollBy(0, 500);
    await sleep(2000);
    followUsers();
  };

  console.log('🚀 Keyword Follow | Search "People" tab first!');
  followUsers();
})();

👀 Monitoring Tools

📊

Monitor Any Account

100% Free

Track follows/unfollows on any public account.

📋 View Full Code
Go to: x.com/TARGET_USER/followers or /following
// Monitor Any Account - by nichxbt
// Track changes on any public account

(() => {
  const sleep = ms => new Promise(r => setTimeout(r, ms));
  const path = window.location.pathname;
  const isFollowers = path.includes('/followers');
  const isFollowing = path.includes('/following');

  if (!isFollowers && !isFollowing) {
    console.error('❌ Go to: x.com/username/followers or /following');
    return;
  }

  const type = isFollowers ? 'followers' : 'following';
  const target = path.split('/')[1].toLowerCase();
  const key = `xactions_${target}_${type}`;

  const scrape = async () => {
    const users = new Set();
    let prev = 0, retries = 0;
    console.log(`🔍 Scanning @${target}'s ${type}...`);

    while (retries < 5) {
      window.scrollTo(0, document.body.scrollHeight);
      await sleep(1500);
      document.querySelectorAll('[data-testid="UserCell"] a[href^="/"]').forEach(el => {
        const u = el.getAttribute('href').replace('/', '').split('/')[0].toLowerCase();
        if (u && u !== target && !u.includes('?')) users.add(u);
      });
      if (users.size === prev) retries++;
      else { retries = 0; prev = users.size; }
    }
    return Array.from(users);
  };

  const run = async () => {
    const current = await scrape();
    const prev = JSON.parse(localStorage.getItem(key) || 'null');

    if (prev) {
      const removed = prev.users.filter(u => !current.includes(u));
      const added = current.filter(u => !prev.users.includes(u));
      console.log(`📊 Previous: ${prev.users.length} | Current: ${current.length}`);
      if (removed.length) console.log(`🚨 REMOVED: ${removed.map(u => '@' + u).join(', ')}`);
      if (added.length) console.log(`🎉 ADDED: ${added.map(u => '@' + u).join(', ')}`);
      if (!removed.length && !added.length) console.log('✨ No changes!');
    } else {
      console.log('📸 First scan! Run again to detect changes.');
    }

    localStorage.setItem(key, JSON.stringify({ users: current, timestamp: new Date().toISOString() }));
    console.log('💾 Saved!');
  };

  run();
})();
🔔

New Follower Alerts

100% Free

Track your new followers over time.

📋 View Full Code
Go to: x.com/YOUR_USERNAME/followers → Run periodically
// New Follower Alerts - by nichxbt

(() => {
  const STORAGE_KEY = 'xactions_new_followers';
  const sleep = ms => new Promise(r => setTimeout(r, ms));

  if (!window.location.pathname.includes('/followers')) {
    console.error('❌ Go to your /followers page!');
    return;
  }

  const username = window.location.pathname.split('/')[1];

  const scrape = async () => {
    const followers = new Map();
    let prev = 0, retries = 0;

    while (retries < 5) {
      window.scrollTo(0, document.body.scrollHeight);
      await sleep(1500);
      document.querySelectorAll('[data-testid="UserCell"]').forEach(cell => {
        const link = cell.querySelector('a[href^="/"]');
        const name = cell.querySelector('[dir="ltr"] > span')?.textContent;
        if (link) {
          const u = link.getAttribute('href').replace('/', '').split('/')[0].toLowerCase();
          if (u && u !== username.toLowerCase()) followers.set(u, name || u);
        }
      });
      if (followers.size === prev) retries++;
      else { retries = 0; prev = followers.size; }
    }
    return followers;
  };

  const run = async () => {
    console.log(`🎉 New Followers Tracker for @${username}`);
    const current = await scrape();
    const prev = JSON.parse(localStorage.getItem(STORAGE_KEY) || 'null');

    if (prev && prev.username.toLowerCase() === username.toLowerCase()) {
      const prevUsers = new Set(Object.keys(prev.followers));
      const newFollowers = [];
      current.forEach((name, user) => {
        if (!prevUsers.has(user)) newFollowers.push({ user, name });
      });

      const change = current.size - prev.count;
      console.log(`📊 Previous: ${prev.count} | Current: ${current.size} (${change >= 0 ? '+' : ''}${change})`);
      if (newFollowers.length) {
        console.log(`🎉 NEW FOLLOWERS (${newFollowers.length}):`);
        newFollowers.forEach(f => console.log(`   ${f.name} (@${f.user})`));
      }
    } else {
      console.log('📸 First scan! Run again to see new followers.');
    }

    localStorage.setItem(STORAGE_KEY, JSON.stringify({
      username, followers: Object.fromEntries(current), count: current.size, timestamp: new Date().toISOString()
    }));
    console.log('💾 Saved!');
  };

  run();
})();

🏠 Community Tools

🚪

Leave All Communities

100% Free

Automatically leave all X Communities you've joined.

📋 View Full Code
Go to: x.com/YOUR_USERNAME/communities → Paste & run
// Leave All Communities - by nichxbt
// 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 getLeft = () => JSON.parse(sessionStorage.getItem('xactions_left') || '[]');
  const markLeft = (id) => {
    const left = getLeft();
    if (!left.includes(id)) {
      left.push(id);
      sessionStorage.setItem('xactions_left', JSON.stringify(left));
    }
  };

  const sleep = ms => new Promise(r => setTimeout(r, ms));

  const run = async () => {
    console.log(`🚀 Left ${getLeft().length} communities so far...`);
    await sleep(1500);

    const joinedBtn = document.querySelector($joinedButton);
    if (joinedBtn) {
      const id = window.location.href.match(/\/i\/communities\/(\d+)/)?.[1];
      console.log(`📍 Leaving community ${id}...`);
      joinedBtn.click();
      await sleep(1000);
      document.querySelector($confirmButton)?.click();
      if (id) markLeft(id);
      await sleep(1500);
      document.querySelector($communitiesNav)?.click();
      await sleep(2500);
      return run();
    }

    const left = getLeft();
    for (const link of document.querySelectorAll($communityLinks)) {
      const id = link.href.match(/\/i\/communities\/(\d+)/)?.[1];
      if (id && !left.includes(id)) {
        console.log(`🏠 Entering community ${id}...`);
        link.click();
        await sleep(2500);
        return run();
      }
    }

    console.log(`🎉 DONE! Left ${getLeft().length} communities.`);
    sessionStorage.removeItem('xactions_left');
  };

  run();
})();

📥 Scraping Tools

🎬

Video Downloader

100% Free

Download any video from X/Twitter posts.

📋 View Full Code
Go to: Any tweet with video → Paste this script
// X Video Downloader - by nichxbt

(() => {
  const findVideos = () => {
    const videos = [];
    const html = document.documentElement.innerHTML;
    const patterns = [
      /https:\/\/video\.twimg\.com\/[^"'\s]+\.mp4[^"'\s]*/g,
      /https:\/\/[^"'\s]*\/amplify_video[^"'\s]*\.mp4[^"'\s]*/g,
      /https:\/\/[^"'\s]*\/ext_tw_video[^"'\s]*\.mp4[^"'\s]*/g,
    ];

    patterns.forEach(pattern => {
      (html.match(pattern) || []).forEach(url => {
        let clean = url.replace(/\\u002F/g, '/').replace(/\\/g, '').split('"')[0].split("'")[0];
        if (clean.includes('.mp4')) {
          const quality = clean.match(/\/(\d+x\d+)\//)?.[1] || 'unknown';
          videos.push({ url: clean, quality });
        }
      });
    });

    // Deduplicate
    const seen = new Set();
    return videos.filter(v => {
      const key = v.url.split('?')[0];
      if (seen.has(key)) return false;
      seen.add(key);
      return true;
    });
  };

  const videos = findVideos();
  if (!videos.length) {
    console.log('❌ No videos found. Make sure you are on a tweet with video.');
    return;
  }

  videos.sort((a, b) => {
    const res = q => parseInt(q.match(/(\d+)x(\d+)/)?.[2] || 0);
    return res(b.quality) - res(a.quality);
  });

  console.log(`🎬 Found ${videos.length} video(s):`);
  videos.forEach((v, i) => console.log(`${i + 1}. [${v.quality}] ${v.url.substring(0, 80)}...`));

  const best = videos[0];
  console.log(`\n📥 Downloading best quality (${best.quality})...`);
  const a = document.createElement('a');
  a.href = best.url;
  a.download = `twitter-video-${Date.now()}.mp4`;
  a.target = '_blank';
  a.click();
})();

🤖 AI & MCP Integration

🔌

MCP Server for AI Agents

100% Free

Connect Claude Desktop or any MCP client to control X/Twitter.

📋 View Setup Instructions
# Install XActions globally
npm install -g xactions

# Or run directly with npx
npx xactions mcp

# Add to Claude Desktop config (~/.claude/config.json):
{
  "mcpServers": {
    "xactions": {
      "command": "npx",
      "args": ["xactions", "mcp"],
      "env": {
        "X_AUTH_TOKEN": "your_auth_token_here"
      }
    }
  }
}

# Available MCP Tools:
# - scrape_profile: Get profile info
# - scrape_followers: Get followers list
# - scrape_following: Get following list
# - scrape_tweets: Get recent tweets
# - unfollow_everyone: Mass unfollow
# - unfollow_non_followers: Smart unfollow
# - detect_unfollowers: Track unfollows
# - auto_like: Like posts by keyword
# - follow_users: Follow user list
# - download_video: Download tweet videos

❓ FAQ

Is this safe to use?

Yes! Browser scripts run entirely in your browser and just automate clicking. Nothing leaves your computer.

Will I get banned?

Scripts include rate limiting, but aggressive automation can trigger spam detection. Use responsibly!

Why is this free?

XActions is 100% open source. Support us by starring on GitHub!