🎉 100% Free & Open Source — No API fees, no subscriptions!

👋 Unfollow Tutorials

Complete guides for mass unfollowing on X/Twitter

🚀 1. Unfollow Everyone

📋 What This Does

Mass unfollows ALL accounts you're currently following. This is the nuclear option - use it when you want to start fresh with a clean following list.

🎯 Quick Start

  1. Go to x.com/YOUR_USERNAME/following
  2. Open DevTools with F12 (Windows/Linux) or Cmd+Option+J (Mac)
  3. Click the "Console" tab
  4. Paste the code below and press Enter
unfollow-everyone.js
// Unfollow everyone on X
// by nichxbt - https://github.com/nirholas/XActions
(() => {
  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`);
      console.log(`RELOAD PAGE AND RE-RUN SCRIPT IF ANY WERE MISSED`);
    } else {
      await sleep({ seconds: 2 });
      return nextBatch();
    }
  };

  nextBatch();
})();
⚠️ Warning

This will unfollow EVERYONE. There's no undo button. Make sure you really want to do this!

⚙️ How It Works

  • Scrolls down your following list to load more accounts
  • Finds all "Following" buttons and clicks them
  • Automatically confirms each unfollow
  • Repeats until no more accounts are found
  • Retries 3 times to catch any stragglers

👥 2. Unfollow Non-Followers Only

📋 What This Does

Unfollows only people who don't follow you back. Keeps mutual follows intact. Perfect for cleaning up your following list without losing your real connections.

🎯 Quick Start

  1. Go to x.com/YOUR_USERNAME/following
  2. Open DevTools (F12 or Cmd+Option+J)
  3. Paste the code below and press Enter
unfollow-non-followers.js
// Unfollow people who don't follow you back
// by nichxbt - https://github.com/nirholas/XActions
(() => {
  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));
    // Filter out users who follow you back (they have the "Follows you" indicator)
    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`);
      console.log(`RELOAD PAGE AND RE-RUN SCRIPT IF ANY WERE MISSED`);
    } else {
      await sleep({ seconds: 2 });
      return nextBatch();
    }
  };

  nextBatch();
})();
💡 How It Detects Mutuals

X shows a "Follows you" badge on users who follow you back. The script looks for [data-testid="userFollowIndicator"] and skips those users.

🧠 3. Smart Unfollow with Whitelist

📋 What This Does

Unfollows non-followers BUT lets you keep specific accounts you want to keep following (like celebrities, brands, or news accounts that never follow back).

🎯 Quick Start

  1. Edit the WHITELIST array with usernames you want to keep
  2. Go to x.com/YOUR_USERNAME/following
  3. Open DevTools and paste the code
smart-unfollow.js
// Smart Unfollow - Non-followers with whitelist
// by nichxbt - https://github.com/nirholas/XActions
(() => {
  // ⬇️ ADD USERNAMES TO KEEP (without @)
  const WHITELIST = [
    'elonmusk',
    'naval',
    'paulg',
    // Add more usernames here...
  ];
  
  const $followButtons = '[data-testid$="-unfollow"]';
  const $confirmButton = '[data-testid="confirmationSheetConfirm"]';
  const $userCell = '[data-testid="UserCell"]';

  let unfollowedCount = 0;
  let skippedCount = 0;
  let retry = { count: 0, limit: 3 };

  const sleep = (ms) => new Promise(r => setTimeout(r, ms));
  const scrollToBottom = () => window.scrollTo(0, document.body.scrollHeight);

  const getUsernameFromCell = (cell) => {
    const link = cell.querySelector('a[href^="/"]');
    if (link) {
      const href = link.getAttribute('href');
      return href.replace('/', '').toLowerCase();
    }
    return null;
  };

  const isWhitelisted = (username) => {
    return WHITELIST.map(u => u.toLowerCase()).includes(username?.toLowerCase());
  };

  const followsBack = (cell) => {
    return cell.querySelector('[data-testid="userFollowIndicator"]') !== null;
  };

  const unfollowUser = async (unfollowBtn) => {
    unfollowBtn.click();
    await sleep(800);
    const confirmBtn = document.querySelector($confirmButton);
    if (confirmBtn) {
      confirmBtn.click();
      await sleep(500);
    }
  };

  const processVisible = async () => {
    const cells = document.querySelectorAll($userCell);
    let processed = 0;

    for (const cell of cells) {
      const username = getUsernameFromCell(cell);
      const unfollowBtn = cell.querySelector($followButtons);
      
      if (!unfollowBtn || !username) continue;

      // Skip if follows back
      if (followsBack(cell)) {
        continue;
      }

      // Skip if whitelisted
      if (isWhitelisted(username)) {
        console.log(`⏭️ Skipping @${username} (whitelisted)`);
        skippedCount++;
        continue;
      }

      console.log(`👋 Unfollowing @${username}...`);
      await unfollowUser(unfollowBtn);
      unfollowedCount++;
      processed++;
      await sleep(1500);
    }

    return processed > 0;
  };

  const run = async () => {
    console.log('🧠 Smart Unfollow Started');
    console.log(`📝 Whitelist: ${WHITELIST.length} accounts protected`);

    while (retry.count < retry.limit) {
      scrollToBottom();
      await sleep(2000);

      const didProcess = await processVisible();
      
      if (!didProcess) {
        retry.count++;
        console.log(`⏳ No users found, retry ${retry.count}/${retry.limit}...`);
      } else {
        retry.count = 0;
      }
    }

    console.log('');
    console.log('✅ DONE!');
    console.log(`👋 Unfollowed: ${unfollowedCount}`);
    console.log(`⏭️ Skipped (whitelisted): ${skippedCount}`);
  };

  run();
})();
✅ Tip

Keep a list of your favorite accounts that never follow back (news, brands, etc.) and add them to your whitelist!

🔍 4. Detect Who Unfollowed You

📋 What This Does

Scans your followers and saves a snapshot. Run it again later to see who unfollowed you! Also shows new followers. Data is saved locally in your browser.

🎯 Quick Start

  1. Go to x.com/YOUR_USERNAME/followers
  2. Open DevTools and paste the code
  3. Wait for scan to complete (saves snapshot)
  4. Run again later to see changes!
detect-unfollowers.js
// Detect who unfollowed you on X
// by nichxbt - https://github.com/nirholas/XActions
(() => {
  const STORAGE_KEY = 'xactions_my_followers';
  const sleep = (ms) => new Promise(r => setTimeout(r, ms));

  // Check we're on the right page
  const isFollowersPage = window.location.pathname.includes('/followers');
  if (!isFollowersPage) {
    console.error('❌ Please navigate to your FOLLOWERS page first!');
    console.log('👉 Go to: https://x.com/YOUR_USERNAME/followers');
    return;
  }

  const getCurrentUsername = () => {
    const match = window.location.pathname.match(/^\/([^/]+)\/followers/);
    return match ? match[1] : 'unknown';
  };

  const scrapeFollowers = async () => {
    const followers = new Set();
    let previousSize = 0;
    let retries = 0;
    const maxRetries = 5;

    console.log('🔍 Scanning your followers...');

    while (retries < maxRetries) {
      // Scroll to load more
      window.scrollTo(0, document.body.scrollHeight);
      await sleep(1500);

      // Find all user cells and extract usernames
      const userCells = document.querySelectorAll('[data-testid="UserCell"]');
      userCells.forEach(cell => {
        const usernameEl = cell.querySelector('a[href^="/"]');
        if (usernameEl) {
          const href = usernameEl.getAttribute('href');
          const username = href.replace('/', '').toLowerCase();
          if (username && !username.includes('/')) {
            followers.add(username);
          }
        }
      });

      console.log(`   Found ${followers.size} followers so far...`);

      if (followers.size === previousSize) {
        retries++;
      } else {
        retries = 0;
        previousSize = followers.size;
      }
    }

    return Array.from(followers);
  };

  const loadPreviousFollowers = () => {
    try {
      const data = localStorage.getItem(STORAGE_KEY);
      if (data) {
        return JSON.parse(data);
      }
    } catch (e) {
      console.warn('Could not load previous data:', e);
    }
    return null;
  };

  const saveFollowers = (followers, username) => {
    const data = {
      username,
      followers,
      timestamp: new Date().toISOString(),
      count: followers.length
    };
    localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
    return data;
  };

  const compareFollowers = (previous, current) => {
    const prevSet = new Set(previous.map(f => f.toLowerCase()));
    const currSet = new Set(current.map(f => f.toLowerCase()));

    const unfollowed = previous.filter(f => !currSet.has(f.toLowerCase()));
    const newFollowers = current.filter(f => !prevSet.has(f.toLowerCase()));

    return { unfollowed, newFollowers };
  };

  const formatDate = (isoString) => {
    return new Date(isoString).toLocaleString();
  };

  const run = async () => {
    const username = getCurrentUsername();
    console.log(`\n🐦 XActions Detector — Monitoring @${username}\n`);

    // Scrape current followers
    const currentFollowers = await scrapeFollowers();
    console.log(`\n✅ Found ${currentFollowers.length} total followers\n`);

    // Check for previous data
    const previousData = loadPreviousFollowers();

    if (previousData && previousData.username === username) {
      console.log(`📊 Comparing with snapshot from ${formatDate(previousData.timestamp)}`);
      console.log(`   Previous count: ${previousData.count}`);
      console.log(`   Current count: ${currentFollowers.length}`);
      console.log('');

      const { unfollowed, newFollowers } = compareFollowers(previousData.followers, currentFollowers);

      if (unfollowed.length > 0) {
        console.log(`\n🚨 ${unfollowed.length} PEOPLE UNFOLLOWED YOU:\n`);
        unfollowed.forEach((u, i) => {
          console.log(`   ${i + 1}. @${u} — https://x.com/${u}`);
        });
      } else {
        console.log('✨ No one unfollowed you since last check!');
      }

      if (newFollowers.length > 0) {
        console.log(`\n🎉 ${newFollowers.length} NEW FOLLOWERS:\n`);
        newFollowers.forEach((u, i) => {
          console.log(`   ${i + 1}. @${u} — https://x.com/${u}`);
        });
      }

      // Offer download of unfollowers
      if (unfollowed.length > 0) {
        const blob = new Blob([unfollowed.join('\n')], { type: 'text/plain' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = `unfollowers-${new Date().toISOString().split('T')[0]}.txt`;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        console.log('\n📥 Downloaded list of unfollowers!');
      }
    } else {
      console.log('📸 First scan! Saving snapshot of your followers...');
      console.log('   Run this script again later to detect changes.');
    }

    // Save current state
    const saved = saveFollowers(currentFollowers, username);
    console.log(`\n💾 Snapshot saved at ${formatDate(saved.timestamp)}`);
    console.log('   Run this script again anytime to check for changes!\n');
  };

  run();
})();
💾 Data Storage

Your follower data is saved in your browser's localStorage under the key xactions_my_followers. It stays on your computer and is never sent anywhere.

📦 Node.js / CLI Method

You can also use XActions from the command line:

Terminal
# Install XActions globally
npm install -g xactions

# Unfollow everyone (requires auth cookie)
npx xactions unfollow --all

# Unfollow non-followers only
npx xactions unfollow --non-followers

# Get list of non-followers
npx xactions analyze non-followers @yourusername

⚠️ Important Notes

  • Rate Limits: X may temporarily limit your account if you unfollow too fast. The scripts include delays to minimize this risk.
  • No Undo: Unfollows cannot be undone automatically. You'd need to re-follow accounts manually.
  • Page Navigation: Don't navigate away while scripts are running - they stop when you leave the page.
  • Large Lists: For accounts following 10,000+ people, run the script multiple times with refreshes.
  • Best Practice: Start during off-peak hours and don't run multiple automation scripts simultaneously.