Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@jalbam
Last active March 20, 2024 03:15
Show Gist options
  • Star 37 You must be signed in to star a gist
  • Fork 15 You must be signed in to fork a gist
  • Save jalbam/d7678c32b6f029c602c0bfb2a72e0c26 to your computer and use it in GitHub Desktop.
Save jalbam/d7678c32b6f029c602c0bfb2a72e0c26 to your computer and use it in GitHub Desktop.
Code to stop following those ones who are not following you back on Twitter and keeping those you want or follow anyone you want, with certain filters (working in July 2019)
/*
Unfollow (stop following) those people who are not following you back on Twitter (or unfollow everyone if desired).
This will work for new Twitter web site code structure (it was changed from July 2019, causing other unfollow-scripts to stop working).
Instructions:
1) The code may need to be modified depending on the language of your Twitter web site:
* For English language web site, no modification needed.
* For Spanish language web site, remember to set the 'LANGUAGE' variable to "ES".
* For another language, remember to set the 'LANGUAGE' variable to that language and modify the 'WORDS' object to add the words in that language.
2) Optionally, you can edit the 'SKIP_USERS' array to insert those users that you do not want to unfollow (even if they are not following you back).
3) If you want to unfollow everyone (except the users in 'SKIP_USERS'), including those who are following you, just set the 'UNFOLLOW_FOLLOWERS' variable to 'true'.
4) You can set the milliseconds per cycle (each call to the 'performUnfollow' function) by modifying the 'MS_PER_CYCLE' variable.
5) If desired, set a number to the 'MAXIMUM_UNFOLLOW_ACTIONS_PER_CYCLE' variable to establish a maximum of unfollow actions to perform for each cycle (each call to the 'performUnfollow' function). Set to null to have no limit.
6) If desired, set a number to the 'MAXIMUM_UNFOLLOW_ACTIONS_TOTAL' variable to establish a maximum of unfollow actions to perform in total for all cycles (all calls to the 'performUnfollow' function). Set to null to have no limit.
7) When the code is fine, on Twitter web site, go to the section where it shows all the people you are following (https://twitter.com/YOUR_USERNAME_HERE/following).
8) Once there, open the JavaScript console (F12 key, normally), paste all the code there and press enter.
9) Wait until you see it has finished. If something goes wrong or some users were not unfollowed, reload the page and repeat from the step 8 again.
* Gist by Joan Alba Maldonado: https://gist.github.com/jalbam/d7678c32b6f029c602c0bfb2a72e0c26
*/
var LANGUAGE = "EN"; //NOTE: change it to use your language!
var WORDS =
{
//English language:
EN:
{
followsYouText: "Follows you", //Text that informs that follows you.
followingButtonText: "Following", //Text of the "Following" button.
confirmationButtonText: "Unfollow" //Text of the confirmation button. I am not totally sure.
},
//Spanish language:
ES:
{
followsYouText: "Te sigue", //Text that informs that follows you.
followingButtonText: "Siguiendo", //Text of the "Following" button.
confirmationButtonText: "Dejar de seguir" //Text of the confirmation button.
},
//Portuguese language (added by gui25 in this fork: https://gist.github.com/gui25/639ac97083b9e3df3ea055f61412674a):
PT:
{
followsYouText: "Segue você", //Text that informs that follows you.
followingButtonText: "Seguindo", //Text of the "Following" button.
confirmationButtonText: "Deixar de Seguir" //Text of the confirmation button.
},
//Indonesian language (added by rllyhz in this fork: https://gist.github.com/rllyhz/280952a6043c32eb7dfad637e335364c):
ID:
{
followsYouText: "Mengikuti Kamu", //Text that informs that follows you.
followingButtonText: "Mengikuti", //Text of the "Following" button.
confirmationButtonText: "Tidak Mengikuti" //Text of the confirmation button.
},
//Turkish language (added by bayramerenn in this fork: https://gist.github.com/bayramerenn/23425a20ab5e4055a687d835744f1905):
TR:
{
followsYouText: "Seni takip ediyor", //Text that informs that follows you.
followingButtonText: "Takip ediliyor", //Text of the "Following" button.
confirmationButtonText: "Takibi bırak" //Text of the confirmation button. I am not totally sure.
}
//NOTE: if needed, add your language here...
}
var UNFOLLOW_FOLLOWERS = false; //If set to true, it will also remove followers (unless they are skipped).
var MS_PER_CYCLE = 10; //Milliseconds per cycle (each call to 'performUnfollow').
var MAXIMUM_UNFOLLOW_ACTIONS_PER_CYCLE = null; //Maximum of unfollow actions to perform, per cycle (each call to 'performUnfollow'). Set to 'null' to have no limit.
var MAXIMUM_UNFOLLOW_ACTIONS_TOTAL = null; //Maximum of unfollow actions to perform, in total (among all calls to 'performUnfollow'). Set to 'null' to have no limit.
var SKIP_USERS = //Users that we do not want to unfollow (even if they are not following you back):
[
//Place the user names that you want to skip here (they will not be unfollowed):
"user_name_to_skip_example_1",
"user_name_to_skip_example_2",
"user_name_to_skip_example_3"
];
SKIP_USERS.forEach(function(value, index) { SKIP_USERS[index] = value.toLowerCase(); }); //Transforms all the user names to lower case as it will be case insensitive.
var _UNFOLLOWED_TOTAL = 0; //Keeps the number of total unfollow actions performed. Read-only (do not modify).
//Function that unfollows non-followers on Twitter:
var performUnfollow = function(followsYouText, followingButtonText, confirmationButtonText, unfollowFollowers, maximumUnfollowActionsPerCycle, maximumUnfollowActionsTotal)
{
var unfollowed = 0;
followsYouText = followsYouText || WORDS.EN.followsYouText; //Text that informs that follows you.
followingButtonText = followingButtonText || WORDS.EN.followingButtonText; //Text of the "Following" button.
confirmationButtonText = confirmationButtonText || WORDS.EN.confirmationButtonText; //Text of the confirmation button.
unfollowFollowers = typeof(unfollowFollowers) === "undefined" || unfollowFollowers === null ? UNFOLLOW_FOLLOWERS : unfollowFollowers;
maximumUnfollowActionsTotal = maximumUnfollowActionsTotal === null || !isNaN(parseInt(maximumUnfollowActionsTotal)) ? maximumUnfollowActionsTotal : MAXIMUM_UNFOLLOW_ACTIONS_TOTAL || null;
maximumUnfollowActionsTotal = !isNaN(parseInt(maximumUnfollowActionsTotal)) ? parseInt(maximumUnfollowActionsTotal) : null;
maximumUnfollowActionsPerCycle = maximumUnfollowActionsPerCycle === null || !isNaN(parseInt(maximumUnfollowActionsPerCycle)) ? maximumUnfollowActionsPerCycle : MAXIMUM_UNFOLLOW_ACTIONS_PER_CYCLE || null;
maximumUnfollowActionsPerCycle = !isNaN(parseInt(maximumUnfollowActionsPerCycle)) ? parseInt(maximumUnfollowActionsPerCycle) : null;
//Looks through all the containers of each user:
var totalLimitReached = false;
var localLimitReached = false;
var userContainers = document.querySelectorAll('[data-testid=UserCell]');
Array.prototype.filter.call
(
userContainers,
function(userContainer)
{
//If we have reached a limit previously, exits silently:
if (totalLimitReached || localLimitReached) { return; }
//If we have reached the maximum desired number of total unfollow actions, exits:
else if (maximumUnfollowActionsTotal !== null && _UNFOLLOWED_TOTAL >= maximumUnfollowActionsTotal) { console.log("Exiting! Limit of unfollow actions in total reached: " + maximumUnfollowActionsTotal); totalLimitReached = true; return; }
//...otherwise, if we have reached the maximum desired number of local unfollow actions, exits:
else if (maximumUnfollowActionsPerCycle !== null && unfollowed >= maximumUnfollowActionsPerCycle) { console.log("Exiting! Limit of unfollow actions per cycle reached: " + maximumUnfollowActionsPerCycle); localLimitReached = true; return; }
//Checks whether the user is following you:
if (!unfollowFollowers)
{
var followsYou = false;
Array.from(userContainer.querySelectorAll("*")).find
(
function(element)
{
if (element.textContent === followsYouText) { followsYou = true; }
}
);
}
else { followsYou = false; } //If we want to also unfollow followers, we consider it is not a follower.
//If the user is not following you (or we also want to unfollow followers):
if (!followsYou)
{
//Finds the user name and checks whether we want to skip this user or not:
var skipUser = false;
var userName = "";
Array.from(userContainer.querySelectorAll("[href^='/']")).find
(
function (element)
{
if (skipUser) { return; }
if (element.href.indexOf("search?q=") !== -1 || element.href.indexOf("/") === -1) { return; }
userName = element.href.substring(element.href.lastIndexOf("/") + 1).toLowerCase();
Array.from(element.querySelectorAll("*")).find
(
function (subElement)
{
if (subElement.textContent.toLowerCase() === "@" + userName)
{
if (SKIP_USERS.indexOf(userName) !== -1)
{
console.log("We want to skip: " + userName);
skipUser = true;
}
}
}
);
}
);
//If we do not want to skip the user:
if (!skipUser)
{
//Finds the unfollow button:
Array.from(userContainer.querySelectorAll('[role=button]')).find
(
function(element)
{
//If the unfollow button is found, clicks it:
if (element.textContent === followingButtonText)
{
console.log("* Unfollowing: " + userName);
element.click();
unfollowed++;
_UNFOLLOWED_TOTAL++;
}
}
);
}
}
}
);
//If there is a confirmation dialog, press it automatically:
Array.from(document.querySelectorAll('[role=button]')).find //Finds the confirmation button.
(
function(element)
{
//If the confirmation button is found, clicks it:
if (element.textContent === confirmationButtonText)
{
element.click();
}
}
);
return totalLimitReached ? null : unfollowed; //If the total limit has been reached, returns null. Otherwise, returns the number of unfollowed people.
}
//Scrolls and unfollows non-followers, constantly:
var scrollAndUnfollow = function()
{
window.scrollTo(0, document.body.scrollHeight);
var unfollowed = performUnfollow(WORDS[LANGUAGE].followsYouText, WORDS[LANGUAGE].followingButtonText, WORDS[LANGUAGE].confirmationButtonText, UNFOLLOW_FOLLOWERS, MAXIMUM_UNFOLLOW_ACTIONS_PER_CYCLE, MAXIMUM_UNFOLLOW_ACTIONS_TOTAL); //For English, you can try to call it without parameters.
if (unfollowed !== null) { setTimeout(scrollAndUnfollow, MS_PER_CYCLE); }
else { console.log("Total desired of unfollow actions performed!"); }
};
scrollAndUnfollow();
@cairey
Copy link

cairey commented Jul 23, 2019

Really nice! Excellent work.

@titojff
Copy link

titojff commented Aug 1, 2019

Excellent work, can you add a counter to stop the script after x unfollows?
It seems Twitter blocks mass unfollowing...

Tanks

@jalbam
Copy link
Author

jalbam commented Aug 1, 2019

Thank you very much for your message. I have modified the code so you can now establish a limit for the unfollow actions performed (per cycle and also in total) by editing the 'MAXIMUM_UNFOLLOW_ACTIONS_PER_CYCLE' and 'MAXIMUM_UNFOLLOW_ACTIONS_TOTAL' variables. Leave their value as null to have no limit.

@iagdotme
Copy link

iagdotme commented Aug 9, 2019

Thanks so much for this script, @jalbam - really beautifully written and so useful!
Sorry if this is a silly question, but could you explain what a cycle is when it comes to your script? It's important to know when putting in the numbers.
The ability to add usernames is really helpful. But I was looking for a way to add all the users I don't want to unfollow. I keep all the users I don't want to unfollow in a Twitter list. Do you think it would be possible to have a script that goes through all the users in a Twitter list and add them to to the console in a format that we can copy and paste into this script? That would be so useful!
Thanks again! :-)

@jalbam
Copy link
Author

jalbam commented Aug 9, 2019

Hello,

Thank you very much for your message.

The script tries to scroll down automatically the Twitter's web site and calls periodically the 'performUnfollow' function, every a certain number of milliseconds (set in the 'MS_PER_CYCLE' variable). Note that, although this function is called after each scroll down action is requested, maybe the web site still did not load new content because takes time to load sometimes.

When I am talking about a cycle I am referring to each call to that 'performUnfollow' function which is the main one performing the unfollowing tasks.

You can put the users you do not want to unfollow in the 'SKIP_USERS' array. I have created the following code (that you can copy and paste in the web site where it shows the people you are following) to print all the usernames (you can set two variables to either skip printing usernames of followers or skip printing usernames non-followers):

/*
	Show user names of people you are following on Twitter, being able to choose certain filters to skip some users (and even skip followers or non-followers).
	
	This will work for new Twitter web site code structure (it was changed from July 2019).
	
	Instructions:
	1) The code may need to be modified depending on the language of your Twitter web site:
		* For English language web site, no modification needed.
		* For Spanish language web site, remember to set the 'LANGUAGE' variable to "ES".
		* For another language, remember to set the 'LANGUAGE' variable to that language and modify the 'WORDS' object to add the words in that language.
	2) If you do not want to print information about whether the user is following you or not, set the 'PRINT_FOLLOW_INFORMATION' variable to false.
	3) Optionally, you can edit the 'SKIP_USERS' array to insert those users whose names you do not want to print.
	4) To skip (do not print) users who are following you, set the 'SKIP_FOLLOWERS' variable to true. Both 'SKIP_FOLLOWERS' and 'SKIP_NON_FOLLOWERS' variables cannot be set to true at the same time.
	5) To skip (do not print) users who are not following you, set the 'SKIP_NON_FOLLOWERS' variable to true. Both 'SKIP_FOLLOWERS' and 'SKIP_NON_FOLLOWERS' variables cannot be set to true at the same time.
	6) You can set the milliseconds per cycle (each call to the 'printUserNames' function) by modifying the 'MS_PER_CYCLE' variable.
	7) When the code is fine, on Twitter web site, go to the section where it shows all the people you are following (https://twitter.com/YOUR_USERNAME_HERE/following).
	8) Once there, open the JavaScript console (F12 key, normally), paste all the code there and press enter.
	9) Wait until you see it has finished. If something goes wrong or some users were not printed, reload the page and repeat from the step 8 again.
	
	* Gist by Joan Alba Maldonado: https://gist.github.com/jalbam/1546b944f5074efd20e5bc838ee138f5
*/


var LANGUAGE = "EN"; //NOTE: change it to use your language!
var WORDS =
{
	//English language:
	EN:
	{
		followsYouText: "Follows you" //Text that informs that follows you.
	},
	//Spanish language:
	ES:
	{
		followsYouText: "Te sigue" //Text that informs that follows you.
	}
	//NOTE: if needed, add your language here...
}
var MS_PER_CYCLE = 10; //Milliseconds per cycle (each call to 'printUserNames').
var PRINT_FOLLOW_INFORMATION = true; //Sets whether to also print information about whether the user follows you or not.
var SKIP_FOLLOWERS = false; //Defines whether to avoid printing user names of followers.
var SKIP_NON_FOLLOWERS = false; //Defines whether to avoid printing user names of non-followers.
var SKIP_USERS = //Users whose name we do not want to print:
[
	//Place the user names that you want to skip here (they will not be printed):
	"user_name_to_skip_example_1",
	"user_name_to_skip_example_2",
	"user_name_to_skip_example_3"
];
SKIP_USERS.forEach(function(value, index) { SKIP_USERS[index] = value.toLowerCase(); }); //Transforms all the user names to lower case as it will be case insensitive.

//Function that names of the users that you are following on Twitter:
var USERS_PRINTED = {}; //Object that will keep the user names printed already and information about whether they are following you or not.
var printUserNames = function(followsYouText, skipFollowers, skipNonFollowers, printFollowInformation)
{
	followsYouText = followsYouText || WORDS.EN.followsYouText; //Text that informs that follows you.
	skipFollowers = (skipFollowers === true || skipFollowers === false) ? skipFollowers : SKIP_FOLLOWERS;
	skipNonFollowers = (skipNonFollowers === true || skipNonFollowers === false) ? skipNonFollowers : SKIP_NON_FOLLOWERS;
	printFollowInformation = (printFollowInformation === true || printFollowInformation === false) ? printFollowInformation : PRINT_FOLLOW_INFORMATION;
	
	if (skipFollowers && skipNonFollowers) { console.log("You cannot skip printing everyone!"); return; }
	
	//Looks through all the containers of each user:
	var userContainers = document.querySelectorAll('[data-testid=UserCell]');
	Array.prototype.filter.call
	(
		userContainers,
		function(userContainer)
		{
			//Checks whether the user is following you:
			var followsYou = false;
			Array.from(userContainer.querySelectorAll("*")).find
			(
				function(element)
				{
					if (element.textContent === followsYouText) { followsYou = true; }
				}
			);

			if (followsYou && skipFollowers) { return; }
			else if (!followsYou && skipNonFollowers) { return; }

			//Finds the user name and checks whether we want to skip this user or not:
			var skipUser = false;
			var userName = "";
			Array.from(userContainer.querySelectorAll("[href^='/']")).find
			(
				function (element)
				{
					if (skipUser) { return; }
					if (element.href.indexOf("search?q=") !== -1 || element.href.indexOf("/") === -1) { return; }
					userName = element.href.substring(element.href.lastIndexOf("/") + 1).toLowerCase();
					Array.from(element.querySelectorAll("*")).find
					(
						function (subElement)
						{
							if (subElement.textContent.toLowerCase() === "@" + userName)
							{
								if (SKIP_USERS.indexOf(userName) !== -1)
								{
									skipUser = true;
								}
							}
						}
					);
				}
			);
			
			//If we do not want to skip the user:
			if (!skipUser)
			{
				//Prints the username:
				if (!USERS_PRINTED[userName])
				{
					console.log("* Username: " + userName + (PRINT_FOLLOW_INFORMATION ? (followsYou ? " follows you" : " does NOT follow you") : ""));
					USERS_PRINTED[userName] = { userName: userName, followsYou: followsYou };
				}
			}
		}
	);
}


//Scrolls and prints usernames, constantly:
var scrollAndShowUsernames = function()
{
	if (SKIP_FOLLOWERS && SKIP_NON_FOLLOWERS) { console.log("You cannot skip printing everyone!"); return; }
	window.scrollTo(0, document.body.scrollHeight);
	printUserNames(WORDS[LANGUAGE].followsYouText, SKIP_FOLLOWERS, SKIP_NON_FOLLOWERS, PRINT_FOLLOW_INFORMATION); //For English, you can try to call it without parameters.
	setTimeout(scrollAndShowUsernames, MS_PER_CYCLE);
};
scrollAndShowUsernames();

This code above has been placed in a newly-created Gist: https://gist.github.com/jalbam/1546b944f5074efd20e5bc838ee138f5

Take care,
Joan

@iagdotme
Copy link

Thanks so much, @jalbam - that all makes sense - and the new script works perfectly.

@jalbam
Copy link
Author

jalbam commented Aug 13, 2019

Thank you very much, I am glad it can be useful.

@jamesbhott
Copy link

Thanks! have you done any work around favorited links? I wrote really crude/crappy code once to isolate links from my favorites to create a reading list but wondering if you have written anything more elegant

@jalbam
Copy link
Author

jalbam commented Feb 6, 2020

No, I have not, sorry. Favourites on Twitter? I have no idea about that. But I am sure there will be plenty of projects/gists here on GitHub related with what you are looking for. Thanks to you.

@musa25
Copy link

musa25 commented Mar 23, 2020

do you have any script for mass follow on twitter??

@jalbam
Copy link
Author

jalbam commented Jun 26, 2020

do you have any script for mass follow on twitter??

No, but it would be easy to modify this one to accomplish that

@vickarma
Copy link

Is it possible to modify the previous script to check the followers of the user you want to unfollow?
For instance, only unfollow user with less than 100 followers?
I can't find the way to do it.

@iagdotme
Copy link

@jalbam I've not tried the script in over a year. Is it still working for you? I'm not getting any errors, but it doesn't seem to be actually unfollowing any accounts.

@jalbam
Copy link
Author

jalbam commented Sep 15, 2021

Hello @iagdotme,

The script is working fine for me but I am using the version in Spanish from Spain of the Twitter web site.

For Spanish from Spain, I have to modify the value of the "LANGUAGE" variable and set it to "ES". For English you could leave it to its default value and it should work that way.

If you are using the script without modifying on the English version of the Twitter web site, please confirm whether maybe they have changed "Follows you", "Following" or "Unfollow" to other sentences. If so, you can modify the script changing the value of these strings that appear in the "WORDS" object (in the "EN" property). If you let me know the new values I can also modify the script.

I hope this helps!

Best regards,
Joan

@raileyb
Copy link

raileyb commented Jun 16, 2023

I'm reading inline code/comment
UNFOLLOW_FOLLOWERS = false; //If set to true, it will also remove followers (unless they are skipped).
which seems to contradict later comments
If you want to follow everyone (except the users in 'SKIP_USERS'), including those who are following you, just set the 'UNFOLLOW_FOLLOWERS' variable to 'true'.

I only want to unfollow those accounts that I currently follow, but are not following me back.
I would think that means setting this flag to false?

@jalbam
Copy link
Author

jalbam commented Jun 16, 2023

Hello,

Thanks for the heads up. The original sentence "If you want to follow everyone..." should be indeed "If you want to unfollow everyone...". I just corrected it.

For your purpose, just leave the "UNFOLLOW_FOLLOWERS" variable set to false.

Cheers,
Joan

@roshanmirajkar
Copy link

Made a version that saves data to CSV. I have some ideas on expanding this project out. Would like to move it into a Repo. Would be cool to use GPT to analyze followers daily, client-side. Open-source.

I have moved this code in a newly-created Gist: https://gist.github.com/roshanmirajkar/afbefda0bd127e0c3df42ac80d6eae6f

Hello,

Thanks for the heads up. The original sentence "If you want to follow everyone..." should be indeed "If you want to unfollow everyone...". I just corrected it.

For your purpose, just leave the "UNFOLLOW_FOLLOWERS" variable set to false.

Cheers, Joan

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment