Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Facebook friends / people search / group members backup in web browser
/* Facebook friends / people search / group members backup in web browser
* Scroll down to your friends page or a people search page to load all profiles
* Copy-paste the script below in a web browser console (F12 key or Ctrl+Shift+K shortcut in a browser like Firefox) and execute the desired function, for example by typing FacebookFriendsBackup() in the console and pressing enter
* A textarea will appear at the end of the page so you can copy the data and paste it in a text file before saving it as a CSV file
* You can then view your backup in a spreadsheet editor like LibreOffice Calc
* You can also compare the backup with another one to see who removed you from their friends list or who appeared in a new search (e.g. with the Linux diff command or awk for column diff https://unix.stackexchange.com/questions/174599/using-diff-on-a-specific-column-in-a-file/174603#174603)
* If the friend changed their name or profile URL, you can still find them with their profile ID which is backed up in the last column (open facebook.com/PROFILE_ID in a web browser)
* The Facebook Graph API was not used because they are locking or deprecating most of their endpoints (e.g. https://developers.facebook.com/docs/graph-api/changelog/breaking-changes/#taggable-friends-4-4)
*/
var data = [];
// to make this script work with the new Facebook, you need to open the mobile web version https://m.facebook.com/username/friends
function FacebookFriendsBackup()
{
var mainList = document.getElementsByClassName("timeline")[0].childNodes[1].childNodes[2].childNodes;
var mainLength = mainList.length;
for (var i = 0; i < mainLength; ++i) {
var list = mainList[i].childNodes;
var length = list.length;
for (var j = 0; j < length; ++j) {
var link = list[j].getElementsByTagName("a")[1];
var count = data.length;
data[count] = link.firstChild.nodeValue;
data[count] += "\t" + link.href;
var friendsButton = list[j].firstChild.childNodes[2];
if (!friendsButton) {
friendsButton = list[j].childNodes[2]; // fix for Chromium (for some reason, Facebook generates a different DOM structure with Firefox)
}
var json = JSON.parse(friendsButton.firstChild.firstChild.childNodes[2].getAttribute("data-store"));
data[count] += "\t" + json.id;
}
}
displayData();
}
// NOT WORKING WITH NEW FACEBOOK (use the updated function above)
function OldFacebookFriendsBackup()
{
var list = document.getElementsByClassName("uiProfileBlockContent");
var length = list.length;
// note: firstChild is a bit faster than firstElementChild: https://jsperf.com/firstelementchild-and-firstchild
for (var i = 0; i < length; ++i) {
var link = list[i].getElementsByTagName("a")[0];
data[i] = link.firstChild.nodeValue;
data[i] += "\t" + link.href;
var json = JSON.parse(link.getAttribute("data-gt"));
if (json) { // JSON data is null when the Facebook profile is deactivated
data[i] += "\t" + json.engagement.eng_tid; // get profile ID in case the Facebook user changes their profile URL
}
}
displayData();
}
// we need to hook AJAX response with JavaScript to get the profile ID since it is not displayed in the DOM (username is not reliable to backup since it can change)
// execute this function before opening the page and scrolling
// https://stackoverflow.com/questions/5202296/add-a-hook-to-all-ajax-requests-on-a-page/27363569#27363569
function FacebookPeopleSearchBackup()
{
var count = 0;
var origOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function() {
if (arguments[1] == "/api/graphql/") {
this.addEventListener("load", function() {
var json = JSON.parse(this.responseText);
var list = json.data.serpResponse.results.edges;
var length = list.length;
for (var i = 0; i < length; ++i) {
var user = list[i].relay_rendering_strategy.view_model.profile;
if (user) {
data[count] = user.id;
// comment previous line and uncomment following lines if you want full name and profile URL also
/*data[count] = user.name;
data[count] += "\t" + user.url;
data[count] += "\t" + user.id;*/
console.log(data[count]);
++count;
}
else {
console.log("END");
displayData();
}
}
});
}
origOpen.apply(this, arguments);
};
}
// NOT WORKING WITH NEW FACEBOOK (use the updated function above)
// can be used to backup a people search
// some results could be missing since sometimes the city name is followed by the region instead of the country
function OldFacebookPeopleSearchBackup()
{
//var list = document.getElementById("browse_result_area").getElementsByClassName("FriendRequestOutgoing"); // missing results since friend button is disabled on some profiles
var list = document.querySelectorAll('#BrowseResultsContainer > div, [data-testid="results"] > div');
var length = list.length;
for (var i = 0; i < length; ++i) {
data[i] = JSON.parse(list[i].firstChild.getAttribute("data-bt")).id;
// comment previous line and uncomment following lines if you want full name and profile URL also
/*var link = list[i].getElementsByTagName("a")[1];
data[i] = link.title;
data[i] += "\t" + link.href;
data[i] += "\t" + JSON.parse(list[i].firstChild.getAttribute("data-bt")).id;*/
}
displayData();
}
// can be used to backup group members with things in common (https://www.facebook.com/groups/XXX/members/things_in_common) or all members
function FacebookGroupMembersBackup()
{
// use XPath since there is no identifier, only random class names
var xpath = "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[4]/div/div/div/div/div/div/div/div[2]/div[1]/div/div[2]/div"; // members with things in common
//var xpath = "/html/body/div[1]/div/div[1]/div/div[3]/div/div/div[1]/div[1]/div[4]/div/div/div/div/div/div/div/div/div/div/div[2]/div[10]/div/div[2]/div"; // all members
var list = $x(xpath)[0].childNodes;
var length = list.length;
for (var i = 0; i < length; ++i) {
var link = list[i].getElementsByTagName("a")[1];
var split = link.href.split("/");
data[i] = split[split.length - 2];
// comment previous line and uncomment following lines if you want full name also
/*data[i] = link.firstChild.nodeValue;
data[i] += "\t" + split[split.length - 2];*/
}
displayData();
}
// NOT WORKING WITH NEW FACEBOOK (use the updated function above)
// can be used to backup group members with things in common (old URL: https://www.facebook.com/groups/XXX/members_with_things_in_common/)
// some results could be missing since sometimes the city uses the original name instead of the translated name
function OldFacebookGroupMembersBackup()
{
var list = document.querySelectorAll("[id^=things_in_common_]"); // members with things in common
var length = list.length;
for (var i = 0; i < length; ++i) {
data[i] = list[i].id.substr(17);
// comment previous line and uncomment following lines if you want full name and profile URL also
/*var link = list[i].getElementsByTagName("a")[1];
data[i] = link.title;
data[i] += "\t" + link.href;
data[i] += "\t" + list[i].id.substr(17);*/
}
displayData();
}
function displayData()
{
var box = document.createElement("textarea");
box.style = "position: relative; z-index: 1"; // show box on top of other elements (needed for the new Facebook with FacebookPeopleSearchBackup())
box.value = data.join('\n');
document.body.appendChild(box);
}
@hoshi411

This comment has been minimized.

Copy link

@hoshi411 hoshi411 commented Mar 21, 2020

What is a web browser console?

@baptx

This comment has been minimized.

Copy link
Owner Author

@baptx baptx commented Mar 21, 2020

@hoshi411 it is a web browser area where you can execute custom JavaScript code, you can open it with the F12 key or Ctrl+Shift+K shortcut in a browser like Firefox (I just updated the script comment to mention this for people who are not familiar with it).

@RollinCajun

This comment has been minimized.

Copy link

@RollinCajun RollinCajun commented May 12, 2021

Where is the textarea suppose to be going? I've done this script in the console a bunch of times and I never see a textarea anywhere on the browser window. I scrolled all the way up and down the friends list to see if it put it somewhere on the page I see nothing. I don't know where I am suppose to copy this data from because I can't find it.

@RollinCajun

This comment has been minimized.

Copy link

@RollinCajun RollinCajun commented May 12, 2021

The actual names and links for each person is inside of an h3 class I may end up just writing something in vb .net to do this because this script does not work in any browser I've tried. I don't know anything about javascript and honestly don't want to learn javascript just to do something this simple but I'm completely confused why you are searching for timeline when everything you need it inside the h3 classes. Search for the first h3 grab all data between <a href and /a> then go to the next h3 till it's at the end then parse the HTML tags out. Maybe facebook changed it again and this script just needs updating.

@baptx

This comment has been minimized.

Copy link
Owner Author

@baptx baptx commented May 12, 2021

@RollinCajun hi, I mentioned it in the script, the textarea will appear at the end of the page (bottom-left to be precise since elements are always on the left by default) but you have to use it on on the mobile web version https://m.facebook.com/username/friends and scroll to the bottom of the page to load all profiles before using the script. I tried it now, it still works.
The reason I used the mobile web version is to get the profile IDs in case usernames change, since Facebook removed the profile IDs from the DOM on the desktop web version.
For your question about h3, the weird thing is that some of the profiles are in h3 and others in h1 for me (at the bottom of the page, for profiles loaded when scrolling). The advantage of not searching for h3 is that you don't rely on the tag name, for example it would break the script if Facebook adds an h3 tag for something else.
Also searching for the h3 tag would not be enough if you want to get the profile ID in addition to the username.

@RollinCajun

This comment has been minimized.

Copy link

@RollinCajun RollinCajun commented May 12, 2021

@RollinCajun hi, I mentioned it in the script, the textarea will appear at the end of the page (bottom-left to be precise since elements are always on the left by default) but you have to use it on on the mobile web version https://m.facebook.com/username/friends and scroll to the bottom of the page to load all profiles before using the script. I tried it now, it still works.
The reason I used the mobile web version is to get the profile IDs in case usernames change, since Facebook removed the profile IDs from the DOM on the desktop web version.
For your question about h3, the weird thing is that some of the profiles are in h3 and others in h1 for me (at the bottom of the page). The advantage of not searching for h3 is that you don't rely on the tag name, for example it would break the script if Facebook adds an h3 tag for something else.

Oh okay well it still doesn't work for me. I have tried it in opera, firefox, and chrome console and it never creates the textarea for me. I'm copying the first code in your script

var data = [];

// to make this script work with the new Facebook, you need to open the mobile web version https://m.facebook.com/username/friends
function FacebookFriendsBackup()
{
	var mainList = document.getElementsByClassName("timeline")[0].childNodes[1].childNodes[2].childNodes;
	var mainLength = mainList.length;
	
	for (var i = 0; i < mainLength; ++i) {
		var list = mainList[i].childNodes;
		var length = list.length;
		
		for (var j = 0; j < length; ++j) {
			var link = list[j].getElementsByTagName("a")[1];
			var count = data.length;
			data[count] = link.firstChild.nodeValue;
			data[count] += "\t" + link.href;
			var json = JSON.parse(list[j].firstChild.childNodes[2].firstChild.firstChild.childNodes[2].getAttribute("data-store"));
			data[count] += "\t" + json.id;
		}
	}
	
	displayData();
}

then I add the last code

function displayData()
{
	var box = document.createElement("textarea");
	box.style = "position: relative; z-index: 1"; // show box on top of other elements (needed for the new Facebook with FacebookPeopleSearchBackup())
	box.value = data.join('\n');
	document.body.appendChild(box);
}

I'm copying all that into the console and hitting enter and I never see a textarea it shows nothing for me on my side.

@RollinCajun

This comment has been minimized.

Copy link

@RollinCajun RollinCajun commented May 12, 2021

Here is a screenshot showing I don't see any textarea at the bottom. There is never one created.

http://i.epvpimg.com/1Wh9aab.png

@baptx

This comment has been minimized.

Copy link
Owner Author

@baptx baptx commented May 12, 2021

@RollinCajun After copy-pasting, did you execute the function by typing FacebookFriendsBackup() and pressing enter in the console? Otherwise do you see an error in the console?
Maybe this comment line of the script was not clear enough for people who don't know JavaScript (but it is similar for other programming languages also):

  • Copy-paste the script below in a web browser console (F12 key or Ctrl+Shift+K shortcut in a browser like Firefox) and execute the desired function
@RollinCajun

This comment has been minimized.

Copy link

@RollinCajun RollinCajun commented May 12, 2021

I copied all the code above that I mentioned and hit the enter key. I was not aware anything else needed to be done. I've used a lot of scripts like this before. I use one all the time for removing pending friend requests after people don't accept me for a while. I've always just pasted it into the console and hit the enter button and it does it's thing.

I posted a screenshot of my browser and the code executed at the right hand side inside the console to show you.

@baptx

This comment has been minimized.

Copy link
Owner Author

@baptx baptx commented May 12, 2021

@RollinCajun in this script, there are 3 different functions that are related, that's why you have to select which one you want to execute.

@RollinCajun

This comment has been minimized.

Copy link

@RollinCajun RollinCajun commented May 12, 2021

When I try to add FacebookFriendsBackup(); at the end of the script, it gives an error every time.

VM4417:13 Uncaught TypeError: list[j].getElementsByTagName is not a function
at FacebookFriendsBackup (:13:23)
at :1:1

@RollinCajun

This comment has been minimized.

Copy link

@RollinCajun RollinCajun commented May 12, 2021

I also didn't copy the other functions I only copied the parts of the script I needed.

@baptx

This comment has been minimized.

Copy link
Owner Author

@baptx baptx commented May 12, 2021

@RollinCajun You got this error with Chrome? With Firefox, it should work. I only used the script with Firefox in the past and when I tried with Chromium, I got this error:

Uncaught TypeError: Cannot read property 'firstChild' of undefined
    at FacebookFriendsBackup (<anonymous>:28:59)
    at <anonymous>:1:1

I updated the script to make it work with Chromium (so it should work with Chrome and other browsers using Chromium now). The problem came from the DOM structure that was different with Firefox, which is not common.

@RollinCajun

This comment has been minimized.

Copy link

@RollinCajun RollinCajun commented May 12, 2021

I guess I just don't know how to use this script because I tried it in all browsers and I still can't get it work. Can you screenshot your browser window with the console open and show me how you are pasting it?

@RollinCajun

This comment has been minimized.

Copy link

@RollinCajun RollinCajun commented May 12, 2021

This is the exact script I'm running in the console and it ERRORS on all browsers

var data = [];

function FacebookFriendsBackup()
{
	var mainList = document.getElementsByClassName("timeline")[0].childNodes[1].childNodes[2].childNodes;
	var mainLength = mainList.length;
	
	for (var i = 0; i < mainLength; ++i) {
		var list = mainList[i].childNodes;
		var length = list.length;
		
		for (var j = 0; j < length; ++j) {
			var link = list[j].getElementsByTagName("a")[1];
			var count = data.length;
			data[count] = link.firstChild.nodeValue;
			data[count] += "\t" + link.href;
			var friendsButton = list[j].firstChild.childNodes[2];
			if (!friendsButton) {
				friendsButton = list[j].childNodes[2];
			}
			var json = JSON.parse(friendsButton.firstChild.firstChild.childNodes[2].getAttribute("data-store"));
			data[count] += "\t" + json.id;
		}
	}
	
	displayData();
}

function displayData()
{
	var box = document.createElement("textarea");
	box.style = "position: relative; z-index: 1";
	box.value = data.join('\n');
	document.body.appendChild(box);
}

FacebookFriendsBackup()

ERROR on Firefox:
Uncaught TypeError: list[j].getElementsByTagName is not a function
FacebookFriendsBackup debugger eval code:13
debugger eval code:1

ERROR on Google Chrome:
Uncaught TypeError: list[j].getElementsByTagName is not a function
at FacebookFriendsBackup (:13:23)
at :37:1

ERROR on Opera:
VM165:13 Uncaught TypeError: list[j].getElementsByTagName is not a function
at FacebookFriendsBackup (:13:23)
at :37:1

@baptx

This comment has been minimized.

Copy link
Owner Author

@baptx baptx commented May 12, 2021

@RollinCajun the screenshot will look like yours, there is nothing interesting to show. But to avoid errors, you can copy-paste everything and when it works, remove what you don't need. I just do an automatic scroll (by pressing the middle click of my mouse) to the bottom to load the list (but when you hit the bottom you have to let it scroll again to the bottom because new content was added, until you cannot scroll anymore), then copy-paste the script, press enter, type FacebookFriendsBackup(), press enter.
Maybe it is not working for you because you have a lot of people in your friends list. I only tested with more than 60. With how many friends did you test? Did you test with the latest version of a web browser like Firefox?
To see if the problem comes from your friends list number, you could test on another Facebook account with less friends to see if it works (or ask someone to test).

Update: I copy-pasted the code you shared and it works fine for me on Firefox and Chromium.

@RollinCajun

This comment has been minimized.

Copy link

@RollinCajun RollinCajun commented May 12, 2021

I always scroll all the way down till I can't scroll anymore. I only have 100 friends so not much more than you. I'm doing exactly what you just mentioned and it is not working for me. All web browsers are up to date and newest version out.

@baptx

This comment has been minimized.

Copy link
Owner Author

@baptx baptx commented May 12, 2021

@RollinCajun it is possible that after 80 or 100 friends, the DOM structure becomes different when loading new friends, which breaks the script. To see when it breaks, you can add the code console.log(i, j); at the beginning of the second for loop and tell me the last numbers you see printed in the console.
By the way, what is the advantage of removing the pending friend requests you sent after some time? I think it is better not to remove them so you can see the requests you already sent in the past (or if it was declined) and some people don't often use Facebook so they could log in once a year or less.

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