Skip to content

Instantly share code, notes, and snippets.

@tedmiston
Last active December 24, 2023 15:43
  • Star 36 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save tedmiston/c7ac401da96b55022aaf to your computer and use it in GitHub Desktop.
Archive all of the messages in your Facebook Messages Inbox

Facebook - Archive All Messages

Because who doesn't have an inbox full of "I got a new phone", event-based group chats, and old lingering messages in their Facebook Messages?

Surprisingly, Facebook has not implemented a way to archive many messages in your inbox. This script provides that solution.

Quickstart

Load Facebook Messages in a new tab.

Open the JavaScript console and paste the contents of jquery.min.js into the console.

Paste the contents of archive-all-facebook-messages.js into the console.

If you want to only test the results before actually running the archiving, there's a param for that:

archive_all(testOnly=true);

When you're ready to run for real:

archive_all();

Caveats

  • Currently only detects the list of messages visible to the user in the page. You can work around this by repeatedly scrolling the message list pane to the bottom until all messages are loaded. I plan to automate this step soon.
  • There is no way to whitelist certain messages from being archived. Currently, you can manually unarchive select messages from the archived view.
  • Sometimes the messages page remains cached after the script reloads it. Reloading it once by hand solves this.
function archive_all(testOnly) {
var someMessages, archiveButton;
if (testOnly === "undefined") { testOnly = false; }
someMessages = $("li._k- span.accessible_elem");
console.log("Found", someMessages.length, "messages to archive in your inbox.");
archiveButton = null;
someMessages.each(function () {
if (testOnly) {
console.log("*DEBUG Only* Archived:", $(this).text());
} else {
archiveButton = $(this).parent().parent().parent().prev().children()[1];
archiveButton.click();
}
});
if (!testOnly) {
location.reload();
}
}
@jhernar
Copy link

jhernar commented Dec 16, 2020

Small change, its a div now...

(function run() {
  let all = document.querySelectorAll('div[aria-label="Menu"]');
  if (all.length == 0) return;
  let a = all[0];
  a.click();
  setTimeout(() => {
    document.querySelectorAll('div[role=menuitem]').forEach(act => {
      if (act.innerText.match(/Hide/)) act.click();
    });
    run();
  }, 500);
})();

Same steps as before, run (https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js) then run the code above.

Fixed! (As at 16-12-2020)

Amazing, thank you so much!!

@smy5
Copy link

smy5 commented Apr 12, 2021

Hello! This worked for me when I tried it last year in October and this year in Jan, but it has since stopped working. It comes up as undefined when I run the https://gist.github.com/tedmiston/c7ac401da96b55022aaf#gistcomment-3562708 version. Does anyone else have this problem?

@oku-da
Copy link

oku-da commented Apr 20, 2021

Hello! This worked for me when I tried it last year in October and this year in Jan, but it has since stopped working. It comes up as undefined when I run the https://gist.github.com/tedmiston/c7ac401da96b55022aaf#gistcomment-3562708 version. Does anyone else have this problem?

Hey @smy5 I had the same issue and I'm a layperson but changing /Hide/ to /Archive/ in the last code shared worked for me.

Such a huge thank you to everybody that has developed this!

This is what I used:

(function run() {
let all = document.querySelectorAll('div[aria-label="Menu"]');
if (all.length == 0) return;
let a = all[0];
a.click();
setTimeout(() => {
document.querySelectorAll('div[role=menuitem]').forEach(act => {
if (act.innerText.match(/Archive/)) act.click();
});
run();
}, 500);
})();

@smy5
Copy link

smy5 commented Apr 20, 2021

Hi @oku-da, thanks for replying. I tried it but it still comes back as undefined. lol layperson too.

@oku-da
Copy link

oku-da commented Apr 20, 2021

When I did it yesterday, it actually did return an "undefined" error in the console, but in the main window I could see the script opening each menu and archiving each message. It basically just automates clicking on the menus, so you should see your browser start to work and after a few minutes of operation it should be complete.

@smy5
Copy link

smy5 commented Apr 20, 2021

@oku-da It worked this time! It took me several tries but I think it's because I forgot to remove my adblocker and scroll down with the new code. Thanks!

@volkankaban
Copy link

(function run() {
let all = document.querySelectorAll('div[aria-label="Menu"]');
if (all.length == 0) return;
let a = all[0];
a.click();
setTimeout(() => {
document.querySelectorAll('div[role=menuitem]').forEach(act => {
if (act.innerText.match(/Archive/)) act.click();
});
run();
}, 500);
})();

Verified!

@l4zehr
Copy link

l4zehr commented May 15, 2021

(function run() {
let all = document.querySelectorAll('div[aria-label="Menu"]');
if (all.length == 0) return;
let a = all[0];
a.click();
setTimeout(() => {
document.querySelectorAll('div[role=menuitem]').forEach(act => {
if (act.innerText.match(/Archive/)) act.click();
});
run();
}, 500);
})();

This worked better on the messenger site than on facebook's site. Pasted the jquery.min.js to the console first. Then I clicked the "..." menu on the top chat, then ran this code on the console. Then, I just waited for the autoclicks to finish. THANK YOU!

@PedroC1999
Copy link

In the latest Messenger, the top right "Menu" is what gets autoclicked, I didn't really have the knowledge to exclude it (I suspect an array.shift() may fix this) but I simply used the Ublock extension to element zap the top "Menu", which let the script run beautifully.

@WhiteDevilWD69
Copy link

(function run() {
let all = document.querySelectorAll('div[aria-label="Menu"]');
if (all.length == 0) return;
let a = all[0];
a.click();
setTimeout(() => {
document.querySelectorAll('div[role=menuitem]').forEach(act => {
if (act.innerText.match(/Archive/)) act.click();
});
run();
}, 500);
})();

This worked better on the messenger site than on facebook's site. Pasted the jquery.min.js to the console first. Then I clicked the "..." menu on the top chat, then ran this code on the console. Then, I just waited for the autoclicks to finish. THANK YOU!

CAN YOU PLEASE HELP ME BY SAYING HOW TO UNARCHIEVE ALL CHATS BACK IN BULK???

@Mariusio
Copy link

This is how I got everything working today:

  1. Right click in top menu bar, find div of top menu in developer tools and completely delete it from DOM
  2. Run https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js in console
  3. Run script from https://gist.github.com/tedmiston/c7ac401da96b55022aaf?permalink_comment_id=3712135#gistcomment-3712135 in console

@jankoweb
Copy link

This works for me - Steps:

  1. open https://www.facebook.com/messages
  2. in Chrome right-click / Explore (in Czech Prozkoumat)
  3. click Console
  4. paste content of http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js (to be able to run the script bellow)
  5. paste this edited code bellow
  • I edited it for the Czech language: Menu=Nabídka, Archive=Archivovat chat)
  • edit let all[0] -> let all[1] (to avoid first step in mentioned in previous message

(function run() { let all = document.querySelectorAll('div[aria-label="Nabídka"]'); if (all.length == 0) return; let a = all[1]; a.click(); setTimeout(() => { document.querySelectorAll('div[role=menuitem]').forEach(act => { if (act.innerText.match(/Archivovat chat/)) act.click(); }); run(); }, 500); })();

@lamyergeier
Copy link

Doesn't work with both: Marketplace messages and normal messages.

@elitetrollz
Copy link

This works for me - Steps:

  1. open https://www.facebook.com/messages
  2. in Chrome right-click / Explore (in Czech Prozkoumat)
  3. click Console
  4. paste content of http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js (to be able to run the script bellow)
  5. paste this edited code bellow
  • I edited it for the Czech language: Menu=Nabídka, Archive=Archivovat chat)
  • edit let all[0] -> let all[1] (to avoid first step in mentioned in previous message

(function run() { let all = document.querySelectorAll('div[aria-label="Nabídka"]'); if (all.length == 0) return; let a = all[1]; a.click(); setTimeout(() => { document.querySelectorAll('div[role=menuitem]').forEach(act => { if (act.innerText.match(/Archivovat chat/)) act.click(); }); run(); }, 500); })();

do this but for English, the code is:
(function run() { let all = document.querySelectorAll('div[aria-label="Menu"]'); if (all.length == 0) return; let a = all[1]; a.click(); setTimeout(() => { document.querySelectorAll('div[role=menuitem]').forEach(act => { if (act.innerText.match(/Archive chat/)) act.click(); }); run(); }, 500); })();

It should be "Archive chat" not "Archive".

@abaddonpro
Copy link

@elitetrollz thank you so much, worked for me as of today!

@DividedGibon
Copy link

DividedGibon commented Jan 16, 2023

Hello - this is my first Github post, so go easy on me :)

I found the code mentioned above was quite slow to run, particularly with Marketplace chats - but did work. It's worth noting I had an exceptionally high number of chats (minimum 2000 plus).

Obviously this is down to the set timeout, the iteration of the function, lack of caching etc. I suggest using the following code which uses requestAnimationFrame, caches 'div[role=menuitem]' etc. There is further improvements that could be made here but this worked a lot quicker for me; not lightning speed but instantly reduces the iteration time from 500ms to however long it takes the browser to be ready to repaint the screen.

(function run() { let all = document.querySelectorAll('div[aria-label="Menu"]'); if (all.length == 0) return; let a = all[1]; a.click(); let menuitems = document.querySelectorAll('div[role=menuitem]'); let archiveChatRegex = /Archive chat/; for (let i = 0; i < menuitems.length; i++) { if (archiveChatRegex.test(menuitems[i].innerText)) { menuitems[i].click(); } } requestAnimationFrame(run); })();

VERSION with white space removed: (function run(){let all=document.querySelectorAll('div[aria-label="Menu"]');if(all.length==0)return;let a=all[1];a.click();let menuitems=document.querySelectorAll('div[role=menuitem]');let archiveChatRegex=/Archive chat/;for(let i=0;i<menuitems.length;i++){if(archiveChatRegex.test(menuitems[i].innerText)){menuitems[i].click();}}requestAnimationFrame(run);})();

Notes
I did not need to paste the http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js contents.
The Dev Console will throw a "[Violation] 'requestAnimationFrame' handler took ms" error for each chat but this can be ignored

@klydeinside
Copy link

klydeinside commented Feb 1, 2023

Thank you so much! I just had 100 Marketplace conversations and this saved me so much time. Also, for easier usage, just drag the code to the bookmarks and then just click it when you need it. It looks like you would need to add javasript tag to the front before it'll work. At least for me on Brave. It would look like so:

javascript: (() => {
(function run(){let all=document.querySelectorAll('div[aria-label="Menu"]');if(all.length==0)return;let a=all[1];a.click();let menuitems=document.querySelectorAll('div[role=menuitem]');let archiveChatRegex=/Archive chat/;for(let i=0;i<menuitems.length;i++){if(archiveChatRegex.test(menuitems[i].innerText)){menuitems[i].click();}}requestAnimationFrame(run);})();
})();

Drag all of that code to your bookmark toolbar and it'll put it there. Then, you can use it whenever you like.

@robovo
Copy link

robovo commented Mar 23, 2023

Thank you all! This has done a heap of tedious cleanup work for me. There is just something so satisfying in seeing things happen on their own instead of your repeating clicking. This is just perfect.

@lamyergeier
Copy link

Would be nice if we could also remove the marketplace messages.

@stacksjb
Copy link

THANK YOU! I've tried several solutions across the internet and this is the first that worked both fast and successfully.

However, I've noticed it doesn't work on archived messages. Any suggestions for the archived chat page?

@DividedGibon
Copy link

Would be nice if we could also remove the marketplace messages.

Did you attempt the code I pasted above? It should also work for market place messages.

@DividedGibon
Copy link

THANK YOU! I've tried several solutions across the internet and this is the first that worked both fast and successfully.

However, I've noticed it doesn't work on archived messages. Any suggestions for the archived chat page?

If it was my code you used (a few comments up) then it won’t work on archived chats as it’s archiving them. Would you want to delete?

@stacksjb
Copy link

stacksjb commented Apr 18, 2023

Hello - this is my first Github post, so go easy on me :)

I found the code mentioned above was quite slow to run, particularly with Marketplace chats - but did work. It's worth noting I had an exceptionally high number of chats (minimum 2000 plus).

Obviously this is down to the set timeout, the iteration of the function, lack of caching etc. I suggest using the following code which uses requestAnimationFrame, caches 'div[role=menuitem]' etc. There is further improvements that could be made here but this worked a lot quicker for me; not lightning speed but instantly reduces the iteration time from 500ms to however long it takes the browser to be ready to repaint the screen.

(function run() { let all = document.querySelectorAll('div[aria-label="Menu"]'); if (all.length == 0) return; let a = all[1]; a.click(); let menuitems = document.querySelectorAll('div[role=menuitem]'); let archiveChatRegex = /Archive chat/; for (let i = 0; i < menuitems.length; i++) { if (archiveChatRegex.test(menuitems[i].innerText)) { menuitems[i].click(); } } requestAnimationFrame(run); })();

VERSION with white space removed: (function run(){let all=document.querySelectorAll('div[aria-label="Menu"]');if(all.length==0)return;let a=all[1];a.click();let menuitems=document.querySelectorAll('div[role=menuitem]');let archiveChatRegex=/Archive chat/;for(let i=0;i<menuitems.length;i++){if(archiveChatRegex.test(menuitems[i].innerText)){menuitems[i].click();}}requestAnimationFrame(run);})();

Notes I did not need to paste the http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js contents. The Dev Console will throw a "[Violation] 'requestAnimationFrame' handler took ms" error for each chat but this can be ignored

I used this version - VERY FAST.

@DividedGibon
Copy link

Hello - this is my first Github post, so go easy on me :)
I found the code mentioned above was quite slow to run, particularly with Marketplace chats - but did work. It's worth noting I had an exceptionally high number of chats (minimum 2000 plus).
Obviously this is down to the set timeout, the iteration of the function, lack of caching etc. I suggest using the following code which uses requestAnimationFrame, caches 'div[role=menuitem]' etc. There is further improvements that could be made here but this worked a lot quicker for me; not lightning speed but instantly reduces the iteration time from 500ms to however long it takes the browser to be ready to repaint the screen.
(function run() { let all = document.querySelectorAll('div[aria-label="Menu"]'); if (all.length == 0) return; let a = all[1]; a.click(); let menuitems = document.querySelectorAll('div[role=menuitem]'); let archiveChatRegex = /Archive chat/; for (let i = 0; i < menuitems.length; i++) { if (archiveChatRegex.test(menuitems[i].innerText)) { menuitems[i].click(); } } requestAnimationFrame(run); })();
VERSION with white space removed: (function run(){let all=document.querySelectorAll('div[aria-label="Menu"]');if(all.length==0)return;let a=all[1];a.click();let menuitems=document.querySelectorAll('div[role=menuitem]');let archiveChatRegex=/Archive chat/;for(let i=0;i<menuitems.length;i++){if(archiveChatRegex.test(menuitems[i].innerText)){menuitems[i].click();}}requestAnimationFrame(run);})();
Notes I did not need to paste the http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js contents. The Dev Console will throw a "[Violation] 'requestAnimationFrame' handler took ms" error for each chat but this can be ignored

I used this version - VERY FAST.

Hi, yes this is mine. This code is archiving the chats it sees, therefore it won’t work on already archived chats. Leave it with me and I’ll re write to delete archived chats.

@xBenji65
Copy link

xBenji65 commented May 7, 2023

Any chance the opposite could be implemented? A way to unarchive all the chats.

@DividedGibon
Copy link

Hi xBenji65. I'm actually just going to set up a separate repo to store the updated code. I'll include a version which does this too. Give me an hour or so.

@DividedGibon
Copy link

Any chance the opposite could be implemented? A way to unarchive all the chats.

Check out here : https://github.com/DividedGibon/Facebook_Messages_Bulk

@DividedGibon
Copy link

THANK YOU! I've tried several solutions across the internet and this is the first that worked both fast and successfully.
However, I've noticed it doesn't work on archived messages. Any suggestions for the archived chat page?

If it was my code you used (a few comments up) then it won’t work on archived chats as it’s archiving them. Would you want to delete?

Check out here : https://github.com/DividedGibon/Facebook_Messages_Bulk

@DividedGibon
Copy link

Would be nice if we could also remove the marketplace messages.

Check out here : https://github.com/DividedGibon/Facebook_Messages_Bulk

@athachai29
Copy link

Thanks a lot

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