Skip to content

Instantly share code, notes, and snippets.

@eznix86
Forked from darraghoriordan/unfollow.js
Last active January 7, 2025 17:29

Revisions

  1. eznix86 revised this gist Jan 7, 2025. 1 changed file with 29 additions and 19 deletions.
    48 changes: 29 additions & 19 deletions unfollow.js
    Original file line number Diff line number Diff line change
    @@ -12,7 +12,6 @@
    (() => {
    const $followButtons = '[data-testid$="-unfollow"]';
    const $confirmButton = '[data-testid="confirmationSheetConfirm"]';

    const retry = {
    count: 0,
    limit: 3,
    @@ -22,35 +21,46 @@
    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 waitForPopup = async () => {
    // Wait for the confirmation popup to appear
    let confirmButton;
    let tries = 0;
    while (!confirmButton && tries < 5) {
    confirmButton = document.querySelector($confirmButton);
    if (!confirmButton) {
    tries++;
    await new Promise(resolve => setTimeout(resolve, 500)); // Wait for 0.5 seconds
    }
    }
    return confirmButton;
    };

    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();
    })
    );
    for (const followButton of followButtons) {
    if (followButton) {
    followButton.click();
    const confirmButton = await waitForPopup();
    if (confirmButton) {
    confirmButton.click();
    } else {
    console.log('Confirmation popup not found, skipping this user.');
    }
    }
    }
    };

    const nextBatch = async () => {
    scrollToTheBottom();
    await sleep({ seconds: 1 });
    await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for 1 second to allow the page to load more buttons

    let followButtons = Array.from(document.querySelectorAll($followButtons));
    followButtons = followButtons.filter(b => b.parentElement?.parentElement?.querySelector('[data-testid="userFollowIndicator"]') === null)
    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 });
    await new Promise(resolve => setTimeout(resolve, 2000)); // Wait for 2 seconds to allow changes to propagate
    return nextBatch();
    } else {
    addNewRetry();
    @@ -60,10 +70,10 @@
    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 });
    await new Promise(resolve => setTimeout(resolve, 2000)); // Wait for 2 seconds
    return nextBatch();
    }
    };

    nextBatch();
    })();
    })();
  2. @darraghoriordan darraghoriordan revised this gist Sep 27, 2023. No changes.
  3. @darraghoriordan darraghoriordan revised this gist Sep 27, 2023. 1 changed file with 6 additions and 2 deletions.
    8 changes: 6 additions & 2 deletions unfollow.js
    Original file line number Diff line number Diff line change
    @@ -1,11 +1,14 @@
    // Unfollow everyone on twitter who doesn't follow you.
    // based on:

    // Unfollow everyone on twitter.com, by Jamie Mason (https://twitter.com/fold_left)
    // https://gist.github.com/JamieMason/7580315
    //
    // 1. Go to https://twitter.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: 09 April 2020
    //
    (() => {
    const $followButtons = '[data-testid$="-unfollow"]';
    const $confirmButton = '[data-testid="confirmationSheetConfirm"]';
    @@ -41,7 +44,8 @@
    scrollToTheBottom();
    await sleep({ seconds: 1 });

    const followButtons = Array.from(document.querySelectorAll($followButtons));
    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) {
  4. @JamieMason JamieMason revised this gist Dec 13, 2021. 1 changed file with 0 additions and 3 deletions.
    3 changes: 0 additions & 3 deletions unfollow.js
    Original file line number Diff line number Diff line change
    @@ -5,9 +5,6 @@
    // 2. Open the Developer Console. (COMMAND+ALT+I on Mac)
    // 3. Paste this into the Developer Console and run it
    //
    // See this tweet by @jacknotlittle for a video showing you how to do it;
    // https://twitter.com/jacknotlittle/status/1387471283525459969
    //
    // Last Updated: 09 April 2020
    (() => {
    const $followButtons = '[data-testid$="-unfollow"]';
  5. @JamieMason JamieMason revised this gist Apr 29, 2021. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions unfollow.js
    Original file line number Diff line number Diff line change
    @@ -5,6 +5,9 @@
    // 2. Open the Developer Console. (COMMAND+ALT+I on Mac)
    // 3. Paste this into the Developer Console and run it
    //
    // See this tweet by @jacknotlittle for a video showing you how to do it;
    // https://twitter.com/jacknotlittle/status/1387471283525459969
    //
    // Last Updated: 09 April 2020
    (() => {
    const $followButtons = '[data-testid$="-unfollow"]';
  6. @JamieMason JamieMason revised this gist Apr 9, 2020. 1 changed file with 42 additions and 22 deletions.
    64 changes: 42 additions & 22 deletions unfollow.js
    Original file line number Diff line number Diff line change
    @@ -4,41 +4,61 @@
    // 1. Go to https://twitter.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: 09 April 2020
    (() => {
    const followButtonQuery = '[data-testid$="-unfollow"]';
    const confirmButtonQuery = '[data-testid="confirmationSheetConfirm"]';
    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 => {
    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 () => {
    window.scrollTo(0, document.body.scrollHeight);
    scrollToTheBottom();
    await sleep({ seconds: 1 });

    const followButtons = Array.from(document.querySelectorAll(followButtonQuery));
    const followButtonCount = followButtons.length;
    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 (followButtonCount === 0) {
    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`);
    return;
    } else {
    await sleep({ seconds: 2 });
    return nextBatch();
    }

    console.log(`UNFOLLOWING ${followButtonCount} USERS...`);

    await Promise.all(
    followButtons.map(async followButton => {
    followButton.click();
    await sleep({ seconds: 1 });
    const confirmButton = document.querySelector(confirmButtonQuery);
    confirmButton.click();
    })
    );

    await sleep({ seconds: 2 });
    nextBatch();
    };

    nextBatch();
  7. @JamieMason JamieMason revised this gist Aug 22, 2019. 1 changed file with 4 additions and 3 deletions.
    7 changes: 4 additions & 3 deletions unfollow.js
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,5 @@
    // ====================
    // UPDATED 13 AUG 2019
    // ====================
    // Unfollow everyone on twitter.com, by Jamie Mason (https://twitter.com/fold_left)
    // https://gist.github.com/JamieMason/7580315
    //
    // 1. Go to https://twitter.com/YOUR_USER_NAME/following
    // 2. Open the Developer Console. (COMMAND+ALT+I on Mac)
    @@ -16,6 +14,9 @@
    });

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

    const followButtons = Array.from(document.querySelectorAll(followButtonQuery));
    const followButtonCount = followButtons.length;

  8. @JamieMason JamieMason revised this gist Aug 13, 2019. 1 changed file with 26 additions and 19 deletions.
    45 changes: 26 additions & 19 deletions unfollow.js
    Original file line number Diff line number Diff line change
    @@ -7,31 +7,38 @@
    // 2. Open the Developer Console. (COMMAND+ALT+I on Mac)
    // 3. Paste this into the Developer Console and run it
    (() => {
    const sleep = ({ seconds }) => new Promise(proceed => setTimeout(proceed, seconds * 1000));
    const followButtonQuery = '[data-testid$="-unfollow"]';
    const confirmButtonQuery = '[data-testid="confirmationSheetConfirm"]';
    const sleep = ({ seconds }) =>
    new Promise(proceed => {
    console.log(`WAITING FOR ${seconds} SECONDS...`);
    setTimeout(proceed, seconds * 1000);
    });

    const nextBatch = async () => {
    const followButtonQuery = '[data-testid$="-unfollow"]';
    const confirmButtonQuery = '[data-testid="confirmationSheetConfirm"]';
    const followButtons = Array.from(document.querySelectorAll(followButtonQuery));
    const followButtonCount = followButtons.length;

    if (followButtonCount > 0) {
    console.log(`UNFOLLOWING ${followButtonCount} USERS...`);
    await Promise.all(
    followButtons.map(async followButton => {
    followButton.click();
    await sleep({ seconds: 1 });
    const confirmBtn = document.querySelector(confirmButtonQuery);
    confirmBtn.click();
    })
    );

    console.log(`WAITING FOR 2 SECONDS...`);
    await sleep({ seconds: 2 });
    nextBatch();
    } else {
    console.log(`I THINK WE'RE DONE, RE-RUN THE SCRIPT IF ANY WERE MISSED`);
    if (followButtonCount === 0) {
    console.log(`NO ACCOUNTS FOUND, SO I THINK WE'RE DONE`);
    console.log(`RELOAD PAGE AND RE-RUN SCRIPT IF ANY WERE MISSED`);
    return;
    }

    console.log(`UNFOLLOWING ${followButtonCount} USERS...`);

    await Promise.all(
    followButtons.map(async followButton => {
    followButton.click();
    await sleep({ seconds: 1 });
    const confirmButton = document.querySelector(confirmButtonQuery);
    confirmButton.click();
    })
    );

    await sleep({ seconds: 2 });
    nextBatch();
    };

    nextBatch();
    })();
  9. @JamieMason JamieMason revised this gist Aug 13, 2019. 1 changed file with 23 additions and 10 deletions.
    33 changes: 23 additions & 10 deletions unfollow.js
    Original file line number Diff line number Diff line change
    @@ -1,21 +1,34 @@
    // ====================
    // UPDATED 23 JULY 2019
    // UPDATED 13 AUG 2019
    // ====================
    // Unfollow everyone on twitter.com, by Jamie Mason (https://twitter.com/fold_left)
    //
    // 1. Go to https://twitter.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
    (() => {
    const nextBatch = () => {
    const waitFor = 2;
    const nextBatch = Array.from(document.querySelectorAll('[data-testid$="-unfollow"]'));
    const batchSize = nextBatch.length;
    if (batchSize > 0) {
    console.log(`UNFOLLOWING ${batchSize} USERS...`);
    nextBatch.forEach((button) => button.click());
    console.log(`WAITING FOR ${waitFor} SECONDS...`);
    setTimeout(nextBatch, waitFor * 1000);
    const sleep = ({ seconds }) => new Promise(proceed => setTimeout(proceed, seconds * 1000));

    const nextBatch = async () => {
    const followButtonQuery = '[data-testid$="-unfollow"]';
    const confirmButtonQuery = '[data-testid="confirmationSheetConfirm"]';
    const followButtons = Array.from(document.querySelectorAll(followButtonQuery));
    const followButtonCount = followButtons.length;

    if (followButtonCount > 0) {
    console.log(`UNFOLLOWING ${followButtonCount} USERS...`);
    await Promise.all(
    followButtons.map(async followButton => {
    followButton.click();
    await sleep({ seconds: 1 });
    const confirmBtn = document.querySelector(confirmButtonQuery);
    confirmBtn.click();
    })
    );

    console.log(`WAITING FOR 2 SECONDS...`);
    await sleep({ seconds: 2 });
    nextBatch();
    } else {
    console.log(`I THINK WE'RE DONE, RE-RUN THE SCRIPT IF ANY WERE MISSED`);
    }
  10. @JamieMason JamieMason revised this gist Jul 23, 2019. 1 changed file with 23 additions and 10 deletions.
    33 changes: 23 additions & 10 deletions unfollow.js
    Original file line number Diff line number Diff line change
    @@ -1,11 +1,24 @@
    // ====================
    // UPDATED 23 JULY 2019
    // ====================
    // Unfollow everyone on twitter.com, by Jamie Mason (https://twitter.com/fold_left)

    // 1. Go to https://twitter.com/following.
    // 2. Keep scrolling to the bottom repeatedly until all your followers are loaded.
    // 3. Run this in your console.
    [].slice.call(document.querySelectorAll('.unfollow-text')).forEach(function(button) {
    button.click();
    });

    // If your browser is freezing because you follow *loads* of people, then try the version
    // in this comment: https://gist.github.com/JamieMason/7580315#gistcomment-2316858
    //
    // 1. Go to https://twitter.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
    (() => {
    const nextBatch = () => {
    const waitFor = 2;
    const nextBatch = Array.from(document.querySelectorAll('[data-testid$="-unfollow"]'));
    const batchSize = nextBatch.length;
    if (batchSize > 0) {
    console.log(`UNFOLLOWING ${batchSize} USERS...`);
    nextBatch.forEach((button) => button.click());
    console.log(`WAITING FOR ${waitFor} SECONDS...`);
    setTimeout(nextBatch, waitFor * 1000);
    } else {
    console.log(`I THINK WE'RE DONE, RE-RUN THE SCRIPT IF ANY WERE MISSED`);
    }
    };
    nextBatch();
    })();
  11. @JamieMason JamieMason revised this gist Jan 10, 2018. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions unfollow.js
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,5 @@
    // Unfollow everyone on twitter.com, by Jamie Mason (https://twitter.com/fold_left)

    // 1. Go to https://twitter.com/following.
    // 2. Keep scrolling to the bottom repeatedly until all your followers are loaded.
    // 3. Run this in your console.
  12. @JamieMason JamieMason revised this gist Jan 10, 2018. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions unfollow.js
    Original file line number Diff line number Diff line change
    @@ -4,3 +4,6 @@
    [].slice.call(document.querySelectorAll('.unfollow-text')).forEach(function(button) {
    button.click();
    });

    // If your browser is freezing because you follow *loads* of people, then try the version
    // in this comment: https://gist.github.com/JamieMason/7580315#gistcomment-2316858
  13. @JamieMason JamieMason revised this gist Jul 16, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion unfollow.js
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    // 1. Go to https://twitter.com/following.
    // 2. Keep scrolling to the bottom repeatedly until all your followers are loaded.
    // 3. Run this in your console.
    [].slice.call(document.querySelectorAll('stream-container .unfollow-text')).forEach(function(button) {
    [].slice.call(document.querySelectorAll('.unfollow-text')).forEach(function(button) {
    button.click();
    });
  14. @JamieMason JamieMason created this gist Nov 21, 2013.
    6 changes: 6 additions & 0 deletions unfollow.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,6 @@
    // 1. Go to https://twitter.com/following.
    // 2. Keep scrolling to the bottom repeatedly until all your followers are loaded.
    // 3. Run this in your console.
    [].slice.call(document.querySelectorAll('stream-container .unfollow-text')).forEach(function(button) {
    button.click();
    });