-
-
Save chaodonghu/c942b6ca8f8c247ccacd3b0123ff3580 to your computer and use it in GitHub Desktop.
// Run GOOGLE CHROME - WORKING AS OF DEC 26 2023 | |
// Please @ me in the comments if this stops working, I will try to get it working again within the month | |
// INSTRUCTIONS | |
// 1. Open Instagram in Chrome | |
// 2. Click on "FOLLOWING" on your Instagram profile | |
// 3. Open developer tools by right clicking on the page and clicking "INSPECT" | |
// 4. Copy the code below and paste in the developer tools console and press enter to run | |
// 5. Script will not run if tab is navigated away from, minimized of unfocused (It is recommended to open a new chrome window or push tab to the side and let script run in background) | |
const unfollowEveryone = (async () => { | |
// Modify these variables to your liking | |
const UNFOLLOW_LIMIT = 800; | |
const BREAK_DURATION = 5 * 60 * 1000; // 5 minutes break | |
const TOTAL_DURATION = 10 * 60 * 1000; // 10 minutes duration - Timeout after 10 minutes | |
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); | |
// Find target button | |
const findButton = (txt) => | |
[...document.querySelectorAll("button").entries()] | |
.map(([pos, btn]) => btn) | |
.filter((btn) => btn.innerText === txt)[0]; | |
console.log("Start unfollowing script..."); | |
let startTime = new Date().getTime(); | |
while (new Date().getTime() - startTime < TOTAL_DURATION) { | |
for (let i = 0; i < UNFOLLOW_LIMIT; i++) { | |
const followingButton = findButton("Following"); | |
if (!followingButton) { | |
continue; | |
} | |
followingButton.scrollIntoViewIfNeeded(); | |
followingButton.click(); | |
await delay(100); | |
const confirmUnfollowButton = findButton("Unfollow"); | |
if (confirmUnfollowButton) { | |
await confirmUnfollowButton.click(); // Wait for the unfollow to complete | |
} | |
// Increase UNFOLLOW_INTERVAL if you are getting rate limited | |
// Set this to 0 unfollow as quickly as possible - not recommended | |
// Random unfollow interval for each follow to avoid rate limiting | |
const UNFOLLOW_INTERVAL = Math.floor(Math.random() * 10 + 1) * 5000; | |
console.log(`Wait ${UNFOLLOW_INTERVAL} milliseconds`); | |
await delay(UNFOLLOW_INTERVAL); | |
console.log(`Unfollowed #${i}`); | |
} | |
console.log(`Taking a break for ${BREAK_DURATION / 1000} seconds...`); | |
await delay(BREAK_DURATION); // Take a break to avoid rate limiting | |
startTime = new Date().getTime(); // Reset start time for the next cycle | |
} | |
console.log("Unfollow script complete!"); | |
})(); |
Sometimes it even shows a number but I still follow no one
Hello?
Why does the followers number just pop back up to some random number which is still less than what used to be...
@Ironyte can you post a screenshot of the problem or elaborate, i'm not understanding the issue. Are you referring to once the script is run even though you follow no one the instagram interface still shows you follow users?
Can you take a screenshot of the console to see if there are any errors that appear.
Why does the followers number just pop back up to some random number which is still less than what used to be...
@Ironyte can you post a screenshot of the problem or elaborate, i'm not understanding the issue. Are you referring to once the script is run even though you follow no one the instagram interface still shows you follow users?
Can you take a screenshot of the console to see if there are any errors that appear.
Thats exactly what happens
Why does the followers number just pop back up to some random number which is still less than what used to be...
@Ironyte can you post a screenshot of the problem or elaborate, i'm not understanding the issue. Are you referring to once the script is run even though you follow no one the instagram interface still shows you follow users?
Can you take a screenshot of the console to see if there are any errors that appear.Thats exactly what happens
Also gotta say I set random timeout to near-zero cause some hacker had added 3k accounts in my following list and I needed my account back to normal as fast as possible
Why does the followers number just pop back up to some random number which is still less than what used to be...
@Ironyte can you post a screenshot of the problem or elaborate, i'm not understanding the issue. Are you referring to once the script is run even though you follow no one the instagram interface still shows you follow users?
Can you take a screenshot of the console to see if there are any errors that appear.Thats exactly what happens
Also gotta say I set random timeout to near-zero cause some hacker had added 3k accounts in my following list and I needed my account back to normal as fast as possible
@Ironyte If you're sending too many requests (AKA unfollows) in a short time, you will get rate limited (or sometimes get banned if you send too many requests in a very very short time). Also, follower numbers increasing means the hacker is still in your account still following more people, so please change your passwords and clean your devices.
minor improvrments to the script which allow it work in Aug 2023, better handles the time between unfollows, and scrolls down to handle the next batch received by AJAX.
// click on unfollow
// open the chrome console
// copy the script into the console
const FOLLOWING_BUTTON_TEXT = 'Following' // CHANGE "FOLLOWING" TO LOCALIZED LANGUAGE AS DISPLAYED ON INSTAGRAM
const UNFOLLOW_BUTTON_TEXT = 'Unfollow' // CHANGE "UNFOLLOW" TO LOCALIZED LANGUAGE AS DISPLAYED ON INSTAGRAM
const MAX_ATTEMPTS_PER_UNFOLLOW = 3 // MAXIMUM # OF ATTEMPTS
const TEXT_XPATH='.//div//text()'
const TEXT_XPATH_UNFOLLOW='text()'
const timeout = (ms) => new Promise(resolve => setTimeout(resolve, ms))
const unfollowSomebody = async () => {
const followingButton = document
.evaluate(`//button[${TEXT_XPATH}="${FOLLOWING_BUTTON_TEXT}"]`, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null)
.singleNodeValue
if (followingButton) {
console.log('Found following button. Clicking ...')
followingButton.click()
console.log('Clicked following button.')
let unfollowButton=null
let attempts = 1
await timeout(2000)
while (attempts < MAX_ATTEMPTS_PER_UNFOLLOW && !unfollowButton) {
console.log(`Attempted to find unfollowButton after delay, attmpe #${attempts++}`)
unfollowButton = document.evaluate(`//button[${TEXT_XPATH_UNFOLLOW}="${UNFOLLOW_BUTTON_TEXT}"]`, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue
attempts=attempts+1;
}
if(unfollowButton){
console.log('Found unfollow button. scrolling to force reload next users and clicking ...')
//unfollowButton.scrollIntoView(true)
unfollowButton.click()
document.querySelector('[class="_aano"]').scrollBy(0,30)
}else{
console.log('NO unfollow button. exiting early ...')
return true // no unfollow button found
}
return false
}else{
console.log('WARNING: NO FOLLOW BUTTON FOUND');
}
return true //stop something wrong no following button was found
}
// INCREASE TIMEOUT IF NECESSARY TO AVOID RESTRICTIONS/LIMITS PER DAY max 1 per minute=>60000 + some random increment
const randomTimeout = () => (Math.floor((Math.random() * 10) + 1) * 1000) + 60000
const unfollowEveryone = async () => {
let shouldStop = false
let count=1;
while (true) {
shouldStop = await unfollowSomebody()
const unfollowTimeout = randomTimeout()
console.log(`Waiting ${unfollowTimeout} seconds. Should stop: ${shouldStop}.`)
await timeout(unfollowTimeout)
console.log(`completed unfollowing processing next, count=${count}`)
count=count+1;
if (count>200) return true; // exit early
if(shouldStop){
count=count+5;
console.log('No follow button found trying to scroll more to force ajax refresh, increased count ');
document.querySelector('[class="_aano"]').scrollBy(0,150);
// try to scroll down a bit more
}
}
console.log('DONE PROCESSING.')
}
unfollowEveryone()
const FOLLOWING_BUTTON_TEXT = 'Following'; // Change to match your localized Instagram version
const UNFOLLOW_BUTTON_TEXT = 'Unfollow'; // Change to match your localized Instagram version
const MAX_ATTEMPTS_PER_UNFOLLOW = 3; // Maximum number of attempts to find the Unfollow button
const MAX_TOTAL_ATTEMPTS = 200; // Maximum total attempts before exiting
const TEXT_XPATH = './/div//text()';
const TEXT_XPATH_UNFOLLOW = 'text()';
// Function to click on the Unfollow button
const unfollowUser = async () => {
const followingButton = document.evaluate(
`//button[${TEXT_XPATH}="${FOLLOWING_BUTTON_TEXT}"]`,
document,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
).singleNodeValue;
if (!followingButton) {
console.log('Following button not found. Exiting...');
return true; // No following button found, script should stop
}
console.log('Found following button. Clicking...');
followingButton.click();
console.log('Clicked following button.');
// Wait for a brief moment
await timeout(2000);
let unfollowButton = null;
let attempts = 1;
while (attempts <= MAX_ATTEMPTS_PER_UNFOLLOW && !unfollowButton) {
console.log(`Attempt ${attempts}: Trying to find Unfollow button...`);
unfollowButton = document.evaluate(
`//button[${TEXT_XPATH_UNFOLLOW}="${UNFOLLOW_BUTTON_TEXT}"]`,
document,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
).singleNodeValue;
attempts++;
await timeout(1000); // Wait for 1 second between attempts
}
if (unfollowButton) {
console.log('Found Unfollow button. Clicking...');
unfollowButton.click();
// Scroll down to force the next set of users to load
const scrollContainer = document.querySelector('[class="_aano"]');
if (scrollContainer) {
scrollContainer.scrollBy(0, 30);
}
} else {
console.log('Unfollow button not found after retries.');
}
return false; // Continue to the next user
};
// Function to add a delay between actions
const timeout = (ms) => new Promise(resolve => setTimeout(resolve, ms));
// Function to control the main unfollow loop
const unfollowEveryone = async () => {
let totalAttempts = 0;
while (totalAttempts < MAX_TOTAL_ATTEMPTS) {
totalAttempts++;
console.log(`Processing user #${totalAttempts}...`);
const shouldStop = await unfollowUser();
if (shouldStop) {
console.log('No more following buttons found. Exiting...');
break; // No more following buttons found, exit the loop
}
const unfollowTimeout = randomTimeout();
console.log(`Waiting ${unfollowTimeout / 1000} seconds before the next user.`);
await timeout(unfollowTimeout);
}
console.log('Done processing.');
};
// Function to generate a random timeout between 60-70 seconds
const randomTimeout = () => (Math.floor((Math.random() * 10) + 1) * 1000) + 60000;
// Start the unfollow process
unfollowEveryone();
This script should be working as of Dec 26 2023. Thanks @DimVat1 for that piece of code, i've added a wait interval and log to your code and added some comments/instructions for users.
Hope this helps!
The script works but only for the 20 or so accounts displayed. It is not able to load more accounts after that. A manual reload of the page is required to refresh the list of accounts.
The script works but only for the 20 or so accounts displayed. It is not able to load more accounts after that. A manual reload of the page is required to refresh the list of accounts.
@superbarney There is a TOTAL_DURATION
on line 18 that defines how long the script runs, by default I have it set at 10 minutes so the script will only run for 10 minutes. This in combination with the UNFOLLOW_INTERVAL
on line 48 which is by default a multiple of 5 seconds. Either increase the TOTAL_DURATION
or decrease the UNFOLLOW_INTERVAL
or play with the UNFOLLOW_LIMIT
and BREAK_DURATION
constants.
I've confirmed it to be still working as intended, a manual reload of the page isn't needed -> https://cdn.zappy.app/883b402c34b4343d3280c20730ee36fa.mp4
@Alaryne Yes both the "Following" modal and the "Followers" modal should work with this script if you're on an account page that is not yours.
If you mean removing followers that follow your account, I haven't tried it but you can modify line 33 and line 40 to find the "Remove" button instead.
@superbarney There is a
TOTAL_DURATION
on line 18 that defines how long the script runs, by default I have it set at 10 minutes so the script will only run for 10 minutes. This in combination with theUNFOLLOW_INTERVAL
on line 48 which is by default a multiple of 5 seconds. Either increase theTOTAL_DURATION
or decrease theUNFOLLOW_INTERVAL
or play with theUNFOLLOW_LIMIT
andBREAK_DURATION
constants.I've confirmed it to be still working as intended, a manual reload of the page isn't needed -> https://cdn.zappy.app/883b402c34b4343d3280c20730ee36fa.mp4
Thanks. I tried again and it did work as intended, although strangely, not consistently. Sometimes, it reaches a point and displays the message "Waiting 300 seconds ..." and it resumes after a period of time, but many times, it hangs at that stage.
I have managed to unfollow close to 3000 accounts with the script but had to do it over the course of about a week. To others seeking to do the same, I'd be patient and not mess with the default values as you will hit the rate limit much faster and be locked out from further reducing followers.
@chaodonghu Thanks for the script, much appreciated.
I can verify that the code operates as intended, but it encounters timeouts. Below is an enhanced version of the code, with a particular focus on respecting Instagram's rate limits—both unofficial and official—to mitigate spam and abuse, and improving error handling.
(async function () {
const UNFOLLOW_LIMIT = 200; // Reduced to stay under potential rate limits
const UNFOLLOW_INTERVAL = 5000; // Increased interval to be more respectful of rate limits
const BREAK_DURATION = 5 * 60 * 1000; // 5 minutes break
const TOTAL_DURATION = 10 * 60 * 1000; // 10 minutes duration
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const findButtonByText = (text) =>
Array.from(document.querySelectorAll("button"))
.find((button) => button.innerText === text);
console.log("Start");
let startTime = Date.now();
let unfollowCount = 0;
while (Date.now() - startTime < TOTAL_DURATION) {
for (let i = 0; i < UNFOLLOW_LIMIT; i++) {
const followButton = findButtonByText("Following");
if (!followButton) {
console.log("No more users to unfollow or unable to find button.");
break;
}
followButton.scrollIntoViewIfNeeded();
followButton.click();
await delay(100); // Short delay to wait for modal
const confirmButton = findButtonByText("Unfollow");
if (confirmButton) {
await confirmButton.click(); // Confirm unfollow
unfollowCount++;
console.log(`Unfollowed #${unfollowCount}`);
} else {
console.log("Confirmation button not found.");
}
await delay(UNFOLLOW_INTERVAL);
}
console.log(`Taking a break for ${BREAK_DURATION / 1000} seconds...`);
await delay(BREAK_DURATION);
startTime = Date.now(); // Reset start time for the next cycle
}
console.log("The end");
})();
- Reduced UNFOLLOW_LIMIT and Increased UNFOLLOW_INTERVAL: These changes help to stay under Instagram's rate limits.
Improved Button Selection: Uses Array.from() for better readability and directly finds the button instead of mapping and then filtering. - Added Basic Logging: Basic logging for when no more follow buttons are found or the confirmation button isn't found, which helps in understanding the script's state.
- Error Handling and Debugging: While explicit error handling isn't added, logging helps identify issues. For actual production scripts, consider try-catch blocks around actions that might fail.
may be a silly question, but how do you stop the code from running?
may be a silly question, but how do you stop the code from running?
@pauldgayle You can refresh the page or manually set a limit to stop it from running after a certain limit as mentioned in the script.
// Modify these variables to your liking
const UNFOLLOW_LIMIT = 800;
const BREAK_DURATION = 5 * 60 * 1000; // 5 minutes break
const TOTAL_DURATION = 10 * 60 * 1000; // 10 minutes duration - Timeout after 10 minutes
thank you!!
is there an easy way to add a list of users I don’t want to unfollow?
is there an easy way to add a list of users I don’t want to unfollow?
@nikko-guy Unfortunately not since the entire script is based on just finding the "Following" button irrespective of the user you are unfollowing.
If you want to add a list of users you don't want to unfollow that would involve finding the "Following" button then the name/username element beside the "Following" button and skipping the iteration if it matches a name/username in some sort of lookup array or object.
Why does the followers number just pop back up to some random number which is still less than what used to be...