Skip to content

Instantly share code, notes, and snippets.

@karbassi
Last active June 15, 2025 21:25
Show Gist options
  • Save karbassi/d7499bf9da6407fde1ff45dcde582a12 to your computer and use it in GitHub Desktop.
Save karbassi/d7499bf9da6407fde1ff45dcde582a12 to your computer and use it in GitHub Desktop.
Archive all messages in Google Messages web app

Archive all messages in Google Messages web app

This code was something I quickly put together to archive over 5000 text messages in Google Messages. I have no idea if Google frowns on this or not, but it's basically the same as if a human sat there and archived all the messages by hand.

Tested and working as of Monday, November 4, 2019.

How to run

  1. Sign into https://messages.google.com/web/
  2. Open Chrome Developers console by going to View > Developer > JavaScript Console.
  3. Copy and paste the code below into console. It should automatically run.

Warning

Don't run any code before you know what it does. Review it and make sure it's safe. I accept no fault if something goes wrong. Google may change their code at anytime and this code may not work. I provide no support.

function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function archive() {
let menu = document.querySelectorAll('button.menu-button');
console.log(menu.length);
if(menu.length) {
menu[0].click();
document.querySelectorAll('button.mat-mdc-menu-item')[0].click()
await sleep(1000);
archive();
}
}
archive();
@thesterns
Copy link

hi, i what i was looking for, tnx/
but i get two errors:


Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'click')
at archive (:11:59)
at :17:1
archive @ VM177:11
(anonymous) @ VM177:17


Promise {: TypeError: Cannot read properties of undefined (reading 'click')
at archive (:11:59)…}
[[Prototype]]
:
Promise
[[PromiseState]]
:
"rejected"
[[PromiseResult]]
:
TypeError: Cannot read properties of undefined (reading 'click') at archive (:11:59) at :17:1
message
:
"Cannot read properties of undefined (reading 'click')"
stack
:
"TypeError: Cannot read properties of undefined (reading 'click')\n at archive (:11:59)\n at :17:1"
[[Prototype]]
:
Error
constructor
:
ƒ TypeError()
message
:
""
name
:
"TypeError"
[[Prototype]]
:
Object
constructor
:
ƒ Error()
message
:
""
name
:
"Error"
toString
:
ƒ toString()
length
:
0
name
:
"toString"
arguments
:
(...)
caller
:
(...)
[[Prototype]]
:
ƒ ()
apply
:
ƒ apply()
arguments
:
(...)
bind
:
ƒ bind()
call
:
ƒ call()
caller
:
(...)
constructor
:
ƒ Function()
length
:
0
name
:
""
toString
:
ƒ toString()
Symbol(Symbol.hasInstance)
:
ƒ Symbol.hasInstance
get arguments
:
ƒ ()
set arguments
:
ƒ ()
get caller
:
ƒ ()
set caller
:
ƒ ()
[[FunctionLocation]]
:

[[Prototype]]
:
Object
[[Prototype]]
:
Object

@karbassi
Copy link
Author

This is from Nov 4, 2019. I doubt the interface for Google Messages webapp is the same anymore.

@thesterns
Copy link

tnx for your reply. can you pls update the code above so it will work again?

@ishanarora
Copy link

@thesterns just replace button.mat-menu-item with button.mat-mdc-menu-item in the above code

@thesterns
Copy link

works great. thanks!

@LeonC510
Copy link

This works great for me!!! Thank you so much; this is exactly what I needed. I had hundreds of conversations in Google messages after migrating from my old phone, and this code helped me put the useless conversations away fast.
Tip: If you could only archive 25 conversations unexpectedly, refresh the webpage and rerun the code. The problem is that the Google Messages web end only loads 25 conversations by default.

@geek111
Copy link

geek111 commented Oct 3, 2024

There is possible add checkbox messeges who i want archive one click? but only this what have checked?

@ctarbet00
Copy link

ctarbet00 commented Jan 13, 2025

Works great for me - 2025-January-13.

Press Command+Option+J (Mac) or Control+Shift+J (Windows, Linux, ChromeOS) to open the Console.

My only issue is that the script works on the messages that have loaded which means you need to scroll down through the list periodically if you have many conversations.

@Chuckiecage
Copy link

Can anyone tell me how this could be modified to either print or download the messages instead, have been searching for days with no useful results. Thanks

@aslamcodes
Copy link

Works great for me!!!

@ryantimjohn
Copy link

ryantimjohn commented Jun 15, 2025

Adding this script to scroll all the way down the nav panel in case you had the same problem I did where all convos didn't load. Can be run simultaneously with the above:

(function scrollToLoadAll() {
  const container = document.querySelector(
    'body > mw-app > mw-bootstrap > div > mw-g-ui-container > main > div > mw-main-container > div > mw-main-nav > mws-conversations-list > nav'
  );

  if (!container) {
    console.error("Scroll container not found.");
    return;
  }

  let lastScrollTop = -1;
  let triesWithoutChange = 0;
  const maxTries = 60; // 60 tries * 1000ms = ~1 minute

  const interval = setInterval(() => {
    container.scrollTop += 500;
    console.log("Scrolling…", container.scrollTop);

    if (container.scrollTop === lastScrollTop) {
      triesWithoutChange++;
      if (triesWithoutChange >= maxTries) {
        clearInterval(interval);
        console.log("Done scrolling: likely all conversations loaded.");
      }
    } else {
      lastScrollTop = container.scrollTop;
      triesWithoutChange = 0; // Reset if progress is made
    }
  }, 1000); // Wait 1 second between scrolls
})();

You might have to change that query selector up top. Use find that in the console by right clicking then inspect element.

@ryantimjohn
Copy link

ryantimjohn commented Jun 15, 2025

Okay, going to share what I ended up with, with some enhanced console logging (ty AI) and some stop functions. Also, if it hits something Google won't let it archive, it goes to the next record. Again, you can run these both at the same time and then just leave it running in the background. (I got a new phone, everything got unarchived and I had to churn through 2k messages 😢 )

to stop run either:

stopScrolling();
stopArchiving();

scroll:

// Global handle so you can stop scrolling manually
window.stopScrolling = () => {
  clearInterval(window.scrollIntervalId);
  console.log("⛔️ Auto-scroll manually stopped.");
};

(function scrollToLoadAll() {
  const container = document.querySelector(
    'body > mw-app > mw-bootstrap > div > mw-g-ui-container > main > div > mw-main-container > div > mw-main-nav > mws-conversations-list > nav'
  );

  if (!container) {
    console.error("❌ Scroll container not found.");
    return;
  }

  let lastScrollTop = -1;
  let triesWithoutChange = 0;
  const maxTries = 60; // 60 tries * 1000ms = ~1 minute

  window.scrollIntervalId = setInterval(() => {
    container.scrollTop += 500;
    console.log("↘️ Scrolling…", container.scrollTop);

    if (container.scrollTop === lastScrollTop) {
      triesWithoutChange++;
      if (triesWithoutChange >= maxTries) {
        clearInterval(window.scrollIntervalId);
        console.log("✅ Done: All conversations likely loaded.");
      }
    } else {
      lastScrollTop = container.scrollTop;
      triesWithoutChange = 0;
    }
  }, 1000);
})();

archive:

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

// Global state
let isArchiving = true;
let currentIndex = 0;

window.stopArchiving = () => {
  isArchiving = false;
  console.log("⛔️ Archiving manually stopped.");
};

async function archive() {
  const menuButtons = document.querySelectorAll('button.menu-button');

  if (!isArchiving) {
    console.log("🛑 Archiving stopped.");
    return;
  }

  if (currentIndex >= menuButtons.length) {
    console.log("🎉 Reached the end of visible conversations.");
    return;
  }

  const currentButton = menuButtons[currentIndex];
  console.log(`📦 Trying to archive item ${currentIndex + 1} of ${menuButtons.length}`);

  try {
    currentButton.click();
    await sleep(300);

    const archiveButtons = document.querySelectorAll('button.mat-mdc-menu-item');
    if (!archiveButtons.length) {
      console.warn("⚠️ Archive button not found. Retrying same item.");
      return archive();
    }

    archiveButtons[0].click();
    await sleep(1000);

    const overlay = document.querySelector('div.cdk-overlay-container');
    const error = overlay?.innerText.includes("Could not archive conversation");

    if (error) {
      console.error("❌ Archive failed for this thread. Skipping to next.");
      currentIndex++; // Increment only on failure
    } else {
      console.log("✅ Archived successfully.");
      // Do NOT increment; conversation list has shifted up
    }

    await sleep(500);
    archive();
  } catch (err) {
    console.error("💥 Unexpected error:", err);
    // Don't increment — retry this item
    await sleep(1000);
    archive();
  }
}

// Start
archive();

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