Skip to content

Instantly share code, notes, and snippets.

@sezgi
Last active January 11, 2019 08:15
Show Gist options
  • Save sezgi/b92dfd70a8c959f760151f5a071c0400 to your computer and use it in GitHub Desktop.
Save sezgi/b92dfd70a8c959f760151f5a071c0400 to your computer and use it in GitHub Desktop.
Deletes all group members from a facebook group except yourself. Leaving the group after running this in the javascript console will delete the group. Tested on Chrome May 29, 2017. If your network is super slow, you might want to increase the timeout delay.
// removes your box from the page so you don't get removed from the group
$$('[data-name=GroupProfileGridItem]')[0].remove();
// member action dropdowns
const actions = $$('.adminActions');
// open all dropdowns so they're added to the DOM
for (var i = 0; i < actions.length; i++) {
$$('.adminActions a')[i] && $$('.adminActions a')[i].click();
}
// leave group buttons
const buttons = $$('[data-testid=leave_group]');
var i = 0;
function removeAll() {
setTimeout(function () {
// click each button
buttons[i].click();
// click confirm button with a half second delay
setTimeout(function() {
document.getElementsByClassName('layerConfirm')[0].click()
}, 500);
i++;
if (i < buttons.length) {
// each time this is called, there will be a 3 second delay
removeAll();
}
}, 3000);
}
removeAll();
@rgrm
Copy link

rgrm commented Jun 1, 2017

I would like to know if I can filter and remove certain members. for example based on their location or added by non-admin members or not active in group since they joined...

@bkerensa
Copy link

bkerensa commented Jun 6, 2017

Just tested this on latest Chrome and on Facebook (They have a new group design) and can confirm it does not work.

Chrome gives some message about Service Worker Termination due to Time Out.

Copy link

ghost commented Jun 10, 2017

It seems to remove me ok, but then just fails with undefined in the console.

@hendisantika
Copy link

It does not work for me (Thursday, 15rd June 2017)
Any suggestion?
Thanks.

@nbouliol
Copy link

In $$('.adminActions a')[i] && $$('.adminActions a')[i].click(); line 9

you have to replace a by button

So it becomes $$('.adminActions button')[i] && $$('.adminActions button')[i].click();

Thanks for the code !

@g2p
Copy link

g2p commented May 10, 2018

The button change isn't a sufficient update, facebook seems to have changed the layout a lot more.

@globalkonvict
Copy link

Worked for me..
I wanted to delete an old group I created.. This saved me time.
PS: Also removed me from the group.

Thanks for writing this

@wcwilson1950
Copy link

wcwilson1950 commented Sep 14, 2018

The structure of the all members section for groups has changed since the above code was written. The code no longer works. I've rewritten the code for the new html hierarchy. I've also modified it to use promises and intervals within the promise to eliminate some of the timeout problems. This code can specify a lower and upper range as well as a max delete queue. Obviously, there are conditions when the script will stop if you aren't deleting all the members at a time, but if multiple people are running this program at the same time on the same group with greater than 5,000 members, the alpha ranges come in handy to have them deleting members across different ranges. It's simplistic, using the first letter of the first name, but works in our use case.
Note: It's really important for the admins to use the excludedFbIds list. If they are first in the delete queue, the deletion stops because they are removed from the group. See instructions below.
`
var deleteAllGroupMembers = (function () {
var deleteAllGroupMembers = {},
// the facebook ids of the users that will not be removed.
// IMPORTANT: add your own facebook id here so that the script will not remove you!
// You can find the id using this: http://findmyfbid.com/
excludedFbIds = ['123456789','987654321'], // make sure each id is a string!
usersToDeleteQueue = [],
scriptEnabled = false, lowAlpha, highAlpha, maxDeletes;

deleteAllGroupMembers.start = function(pLowAlpha,pHighAlpha,maxDeletes) {
	lowAlpha = (pLowAlpha || 'a').toLowerCase();
	highAlpha = (pHighAlpha || 'z').toLowerCase();
	maxDeletes = maxDeletes || 100;
	scriptEnabled = true;
	deleteAll();
};
deleteAllGroupMembers.stop = function() {
	scriptEnabled = false;
};

function deleteAll() {
	if (scriptEnabled) {
		queueMembersToDelete();
		if (usersToDeleteQueue.length > 0) {
			removeNext();
		}
		//processQueue();
	}
}
function getFieldParm(field,parm) {
	var ipos, epos;
	if (field.indexOf(parm + '=') > 0) {
		ipos = field.indexOf(parm + '=') + parm.length + 1;
		epos = field.indexOf('&',ipos) > 0 ? field.indexOf('&',ipos) : field.length;
		return field.substring(ipos,epos);
	}
	return '';
}
function is_null_empty(value) {
	return value === null || value === '';
}
function getElementsByAttribute(el,attrName, attrValue) {
	return el.querySelectorAll('['+attrName+'=' + '"'+attrValue+'"]');
}
function queueMembersToDelete() {
	var count,idx, profileDiv = document.getElementById('groupsMemberSection_all_members'), profiles = getElementsByAttribute(profileDiv,'data-name','GroupProfileGridItem');
	count = profiles.length;
	// For each profile, get the id, name and button to click to Leave Group
	for (idx = 0;idx < count;idx++) {
		memberDiv = profiles[idx];
		var profileImg = memberDiv.getElementsByTagName('img'), fbMemberName, fbMemberIdv, gearWheelIconDiv, ary, firstLetter;
		if (profileImg.length > 0) {		
			fbMemberName = profileImg[0].getAttribute('aria-label');
			firstLetter = fbMemberName[0].toLowerCase();
			if (firstLetter >= lowAlpha && firstLetter <= highAlpha) {
				fbMemberId = getFieldParm(profileImg[0].parentNode.getAttribute('ajaxify'),'member_id');
				if (excludedFbIds.indexOf(fbMemberId) != -1) {
					console.log("SKIPPING "+fbMemberName+' ('+fbMemberId+')');
				} else {
					ary = getElementsByAttribute(memberDiv,'aria-label','Member Settings');
					if (ary.length > 0) {
						usersToDeleteQueue.push({'memberId': fbMemberId,'memberName' : fbMemberName, 'fbSettingsBtn': ary[0]});
						if (usersToDeleteQueue.length >= maxDeletes) {
							break;
						}	
					}
				}
			}
		}
	};
}

function removeNext() {
	if (!scriptEnabled) {
		return;
	}
	if (usersToDeleteQueue.length > 0) {
		var nextElement = usersToDeleteQueue.shift();
		removeMember(nextElement);
	} else {
		deleteAll();
	}
}

function removeMember(memberToRemove) {
	var testForMenuItem = function(resolve, reject) { 
			var interval = setInterval(function(){
					var menuId = memberToRemove.fbSettingsBtn.getAttribute('aria-controls');
					if (!is_null_empty(menuId)) {
						clearInterval(interval);
						resolve(menuId);
					}
				},150);
		}, waitForConfirm = function(memberId, memberName,startCount) {
			     return function(resolve, reject) { 
			var state = 0, interval = setInterval(function(){
				if (state === 0) {
					var btn = document.getElementsByClassName('layerConfirm uiOverlayButton selected');
					if (btn.length > 0) {							
						btn[0].click();
						state = 1;
					}
				} else {
					if (document.forms.length === startCount) {
						resolve({id: memberId, name: memberName});
					}
				}
				},150);
			};
		}, promise, p2;
	memberToRemove.fbSettingsBtn.click();
	promise = new Promise(testForMenuItem);
	promise.then(function(value){
		var removeItem;
		removeItem = getElementsByAttribute(document.getElementById(value), "data-testid", 'leave_group');
		if (removeItem.length > 0) {
			removeItem[0].click();				
			p2 = new Promise(waitForConfirm(memberToRemove.memberId, memberToRemove.memberName, document.forms.length));
			p2.then(function(obj){
				console.log('Member: ' + obj.name + ' (' + obj.id + ')');
				removeNext();
			});
		} else {
			console.log('link not found.');
		}
	});
		
}
return deleteAllGroupMembers;

})();
deleteAllGroupMembers.start('a','m',100);`

@EdoFazlinovic
Copy link

The structure of the all members section for groups has changed since the above code was written. The code no longer works. I've rewritten the code for the new html hierarchy. I've also modified it to use promises and intervals within the promise to eliminate some of the timeout problems. This code can specify a lower and upper range as well as a max delete queue. Obviously, there are conditions when the script will stop if you aren't deleting all the members at a time, but if multiple people are running this program at the same time on the same group with greater than 5,000 members, the alpha ranges come in handy to have them deleting members across different ranges. It's simplistic, using the first letter of the first name, but works in our use case.
Note: It's really important for the admins to use the excludedFbIds list. If they are first in the delete queue, the deletion stops because they are removed from the group. See instructions below.
`
var deleteAllGroupMembers = (function () {
var deleteAllGroupMembers = {},
// the facebook ids of the users that will not be removed.
// IMPORTANT: add your own facebook id here so that the script will not remove you!
// You can find the id using this: http://findmyfbid.com/
excludedFbIds = ['123456789','987654321'], // make sure each id is a string!
usersToDeleteQueue = [],
scriptEnabled = false, lowAlpha, highAlpha, maxDeletes;

deleteAllGroupMembers.start = function(pLowAlpha,pHighAlpha,maxDeletes) {
	lowAlpha = (pLowAlpha || 'a').toLowerCase();
	highAlpha = (pHighAlpha || 'z').toLowerCase();
	maxDeletes = maxDeletes || 100;
	scriptEnabled = true;
	deleteAll();
};
deleteAllGroupMembers.stop = function() {
	scriptEnabled = false;
};

function deleteAll() {
	if (scriptEnabled) {
		queueMembersToDelete();
		if (usersToDeleteQueue.length > 0) {
			removeNext();
		}
		//processQueue();
	}
}
function getFieldParm(field,parm) {
	var ipos, epos;
	if (field.indexOf(parm + '=') > 0) {
		ipos = field.indexOf(parm + '=') + parm.length + 1;
		epos = field.indexOf('&',ipos) > 0 ? field.indexOf('&',ipos) : field.length;
		return field.substring(ipos,epos);
	}
	return '';
}
function is_null_empty(value) {
	return value === null || value === '';
}
function getElementsByAttribute(el,attrName, attrValue) {
	return el.querySelectorAll('['+attrName+'=' + '"'+attrValue+'"]');
}
function queueMembersToDelete() {
	var count,idx, profileDiv = document.getElementById('groupsMemberSection_all_members'), profiles = getElementsByAttribute(profileDiv,'data-name','GroupProfileGridItem');
	count = profiles.length;
	// For each profile, get the id, name and button to click to Leave Group
	for (idx = 0;idx < count;idx++) {
		memberDiv = profiles[idx];
		var profileImg = memberDiv.getElementsByTagName('img'), fbMemberName, fbMemberIdv, gearWheelIconDiv, ary, firstLetter;
		if (profileImg.length > 0) {		
			fbMemberName = profileImg[0].getAttribute('aria-label');
			firstLetter = fbMemberName[0].toLowerCase();
			if (firstLetter >= lowAlpha && firstLetter <= highAlpha) {
				fbMemberId = getFieldParm(profileImg[0].parentNode.getAttribute('ajaxify'),'member_id');
				if (excludedFbIds.indexOf(fbMemberId) != -1) {
					console.log("SKIPPING "+fbMemberName+' ('+fbMemberId+')');
				} else {
					ary = getElementsByAttribute(memberDiv,'aria-label','Member Settings');
					if (ary.length > 0) {
						usersToDeleteQueue.push({'memberId': fbMemberId,'memberName' : fbMemberName, 'fbSettingsBtn': ary[0]});
						if (usersToDeleteQueue.length >= maxDeletes) {
							break;
						}	
					}
				}
			}
		}
	};
}

function removeNext() {
	if (!scriptEnabled) {
		return;
	}
	if (usersToDeleteQueue.length > 0) {
		var nextElement = usersToDeleteQueue.shift();
		removeMember(nextElement);
	} else {
		deleteAll();
	}
}

function removeMember(memberToRemove) {
	var testForMenuItem = function(resolve, reject) { 
			var interval = setInterval(function(){
					var menuId = memberToRemove.fbSettingsBtn.getAttribute('aria-controls');
					if (!is_null_empty(menuId)) {
						clearInterval(interval);
						resolve(menuId);
					}
				},150);
		}, waitForConfirm = function(memberId, memberName,startCount) {
			     return function(resolve, reject) { 
			var state = 0, interval = setInterval(function(){
				if (state === 0) {
					var btn = document.getElementsByClassName('layerConfirm uiOverlayButton selected');
					if (btn.length > 0) {							
						btn[0].click();
						state = 1;
					}
				} else {
					if (document.forms.length === startCount) {
						resolve({id: memberId, name: memberName});
					}
				}
				},150);
			};
		}, promise, p2;
	memberToRemove.fbSettingsBtn.click();
	promise = new Promise(testForMenuItem);
	promise.then(function(value){
		var removeItem;
		removeItem = getElementsByAttribute(document.getElementById(value), "data-testid", 'leave_group');
		if (removeItem.length > 0) {
			removeItem[0].click();				
			p2 = new Promise(waitForConfirm(memberToRemove.memberId, memberToRemove.memberName, document.forms.length));
			p2.then(function(obj){
				console.log('Member: ' + obj.name + ' (' + obj.id + ')');
				removeNext();
			});
		} else {
			console.log('link not found.');
		}
	});
		
}
return deleteAllGroupMembers;

})();
deleteAllGroupMembers.start('a','m',100);`

Can you copy - paste what i need to do? This code doesn't work

@wcwilson1950
Copy link

wcwilson1950 commented Sep 15, 2018

The code does work. It was used to delete a group of about 13,000 members in about 8 hours. Multiple people ran it.

  1. Make sure you edit the excludedFbIds and enter your own Facebook ID so it doesn’t delete you first. You can find it here: http://findmyfbid.com/.
  2. Edit the last line of the above.There are 2 ways to execute the program: the one above deletes group members whose first name begins with a thru m. You can change the range to something else. The other way is to remove everything between the parenthesis and the program will delete everything. i.e.: deleteAllGroupMembers.start()
  3. In Firefox, You need to go to the group you want to delete. You must be an admin.
  4. Click on Members.
  5. Open the Tools | Web Developer | Web Console.
  6. Copy/Paste the code in the JavaScript console. It could fail after a while. Reload it.

@ManuelITEC
Copy link

ManuelITEC commented Jan 10, 2019

The code does work. It was used to delete a group of about 13,000 members in about 8 hours. Multiple people ran it.

  1. Make sure you edit the excludedFbIds and enter your own Facebook ID so it doesn’t delete you first. You can find it here: http://findmyfbid.com/.
  2. Edit the last line of the above.There are 2 ways to execute the program: the one above deletes group members whose first name begins with a thru m. You can change the range to something else. The other way is to remove everything between the parenthesis and the program will delete everything. i.e.: deleteAllGroupMembers.start()
  3. In Firefox, You need to go to the group you want to delete. You must be an admin.
  4. Click on Members.
  5. Open the Tools | Web Developer | Web Console.
  6. Copy/Paste the code in the JavaScript console. It could fail after a while. Reload it.

Hi @wcwilson1950, your script worked but then it failed. I've reloaded it but keep appear this error:

Uncaught TypeError: Cannot read property 'indexOf' of null
    at getFieldParm (<anonymous>:33:12)
    at queueMembersToDelete (<anonymous>:57:18)
    at deleteAll (<anonymous>:24:3)
    at Object.deleteAllGroupMembers.start (<anonymous>:16:2)
    at <anonymous>:132:23

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