Skip to content

Instantly share code, notes, and snippets.

@rcx
Forked from niahoo/delete-all-messages.js
Last active November 9, 2023 19:12
Show Gist options
  • Star 29 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save rcx/a29eac843a8ecf97a22accb34ef60b88 to your computer and use it in GitHub Desktop.
Save rcx/a29eac843a8ecf97a22accb34ef60b88 to your computer and use it in GitHub Desktop.
Delete all your messages in a Discord channel
/*
* Discord: Don't copy stuff into this box
* Me: dOn'T COpy sTuFf iNtO tHIs bOx
*/
clearMessages = function (guild_id, author_id, authToken, deleted = new Set()) {
if (guild_id[0] == "_" && guild_id[guild_id.length - 1] == "_") {
alert("Oops! You forgot to set the guild_id. Please fill it in.")
return;
}
if (author_id[0] == "_" && author_id[author_id.length - 1] == "_") {
alert("Oops! You forgot to set the author_id. Please fill it in.")
return;
}
const searchURL = `https://discordapp.com/api/v9/guilds/${guild_id}/messages/search?author_id=${author_id}&include_nsfw=true&sort_by=timestamp&sort_order=asc`
const headers = { Authorization: authToken }
let clock = 0
interval = 3000
function delay(duration) {
return new Promise((resolve, reject) => {
setTimeout(resolve, duration)
})
}
function loadMessages() {
return fetch(searchURL, { headers })
}
function tryDeleteMessage(message) {
// RAce coNDItiOn
if (!deleted.has(message.id)) { // skip already deleted messages
console.log(`Deleting message ${message.id} from ${message.author.username} (${message.content}...)`)
return fetch(`https://discordapp.com/api/v9/channels/${message.channel_id}/messages/${message.id}`, { headers, method: 'DELETE' })
}
}
let messagesStore = []
loadMessages()
.then(resp => resp.json())
.then(messages => {
messages = messages.messages
if (messages === undefined || messages === null || messages.length == 0) {
console.log(`Couldn't load messages. Check guild id, author id, and auth token.`)
return
}
messages = messages.filter(m => m) // clean undefined
messages = [].concat.apply([], messages); // flatten
messages = messages.filter(m => m) // clean undefined
if (messages.length === 0) {
console.log(`Couldn't load messages. Check guild id, author id, and auth token.`)
return
}
// only delete hits
messages = messages.filter(m => m.hit == true)
// unique by id
messages = messages.filter((e, i) => messages.findIndex(a => a.id === e.id) === i);
beforeId = messages[messages.length-1].id
messagesStore = messagesStore.concat(messages)
return Promise.all(messagesStore.map(message => {
return delay(clock += interval)
.then(() => tryDeleteMessage(message))
.then(resp => {
if (resp) {
if (resp.status == 429) {
interval += 100
console.log(`Too fast; bumping interval to ${interval}`)
} else if (resp.status === 204) {
deleted.add(message.id) // mark deleted
return resp.text()
}
}
})
}))
})
.then(function() {
if (messagesStore.length !== 0) {
clearMessages(guild_id, author_id, authToken, deleted)
} else {
console.log(`We have loaded all messages in this chat.`)
}
})
}
// If the script is having trouble automatically grabbing auth token, please fill it in manually here. Check README for instructions.
authToken = "";
guild_id = '____________guild_id_here_______________'
author_id = '____________author_id_here______________'
function grabAuthTokenFast() {
var localToken = document.body.appendChild(document.createElement(`iframe`)).contentWindow.localStorage.token;
if (localToken !== undefined) {
authToken = JSON.parse(localToken);
return true;
}
return false;
}
function grabAuthToken() {
if (authToken.length === 0) {
// Lmao bypass token security measures
window.onbeforeunload = grabAuthToken;
window.location.reload();
// yoink
var localToken = document.body.appendChild(document.createElement(`iframe`)).contentWindow.localStorage.token;
if (localToken !== undefined) {
authToken = JSON.parse(localToken);
setTimeout(main, 100, authToken);
}
}
return false;
}
function main(authToken) {
if (authToken.length !== 0) {
console.log(`Successfully grabbed your auth token: ` + authToken)
console.log(`Don't share this token with anyone!`)
clearMessages(guild_id, author_id, authToken);
} else {
console.log(`Getting the auth token from localStorage isn't supported on your client. Use Firefox or grab it from a network request's headers.`)
console.log(`To do that go to the Network tab of your inspector and copy the Authorization header of a request. There are detailed instructions in the README.`)
}
}
if (grabAuthTokenFast()) {
console.log("Successfully grabbed auth token using easy method");
main(authToken);
} else {
window.alert("Grabbing your auth token. If a confirm window shows up, please click 'Cancel' in Chrome / 'Stay on Page' in Firefox.");
if (authToken.length !== 0) {
main(authToken);
} else {
grabAuthToken();
}
}

Delete all messages in a Discord channel

This works best in Firefox, I haven't tested it in Chrome. On the desktop client, it may have trouble getting the Auth token from LocalStorage so you need to grab it from a request's headers and replace the parameter "authToken" on the last line with it. There's instructions on how to do that below.

Preqrequisites:

  • computer
  • general knowledge of your browser's inspector/developer tools
  • possibly even a brain

1. Grab guild and author ids

The script uses the internal id values Discord refers to the selected server and user by. The easy way to do this is to enable Developer Mode in your Discord settings, after which you can simply right click the server's icon and your name and click "Copy ID". Otherwise, you can grab the server's id from the URL, and you can get your own id using the network tab of your browser's inspector.

2. Get your authorization token (now automated)

This is now automated thanks to @cntVertex, despite Discord "hiding" the token from localStorage and the DOM. If it isn't able to automatically grab it then you need to get it from a network request. Follow these easy steps:

  1. Open the inspector (Ctrl-Shift-I)
  2. Open the Network tab of your inspector
  3. Open any request to Discord's servers
  4. Look for the "Authorization" request header. Copy that into the line var authToken = "". For example it might look like var authToken = "mfa.a9ushg92ru9gh9ufhsgjuidfhsgiojfhgjishefrgih3er9u3rg_asdfu9ghauisdfhguiahsdguiahsdigua"

3. Get the script

Copy-paste the script into the javascript console, and replace ____________guild_id_here_______________ and ____________author_id_here______________ with the respective ids copied in Step 1.

4. Launch

Strike the Return key on your keyboard...come on, this is not rocket science man.

Also if it does not get your auth token successfully the first time just try running it again.

FAQ

  • How do I use this to delete DMs? Replace searchURL with https://discordapp.com/api/v6/channels/${guild_id}/messages/search?author_id=${author_id}&include_nsfw=true. For example, replace this line:
const searchURL = `https://discordapp.com/api/v8/guilds/${guild_id}/messages/search?author_id=${author_id}&include_nsfw=true`

with

const searchURL = `https://discordapp.com/api/v8/channels/${guild_id}/messages/search?author_id=${author_id}&include_nsfw=true`

The guild_id however isn't the ID of the person who you are DMing. It is actually the ID of the channel of the DM which is a subtle but important distinction. I'm not aware of any easy way to grab this other than to just look at the network inspector under the developer tools.

  • How to delete by oldest messages first?

Add &sort_by=timestamp&sort_order=asc to searchURL

  • How to only delete messages containing some text "abcd"?

Add &content=whatever into the searchURL. For example, https://discordapp.com/api/v6/channels/${guild_id}/messages/search?author_id=${author_id}&include_nsfw=true&content=badword to delete only messages containing "badword".

  • (By @ivmirx) If you want to delete messages before a specific date, do the following:
  1. Open any server to make the search field visible.
  2. Open the "Network" tab in the inspector and clean it from old requests with the trash can icon.
  3. Click in Discord's search field to show the dropdown, then click the "before" option.
  4. Select the date in the calendar.
  5. In the "Network" tab look for the request that contains ?max_id=....
  6. Click on it and copy the max_id=... part from the URL on the right.
  7. Append it to the script's request in the Line 6 by using &.

So now you should have something like: https://discordapp.com/api/v6/guilds/${guild_id}/messages/search?author_id=${author_id}&include_nsfw=true&max_id=540727993958400000 (this example is for 2019-02-01). Also, by manually picking searchURL, you can delete messages matching a certain query, like mentioning someone, containing certain words, etc.

  • Is there a python version of this script so I can run it without opening Discord

Yes

@ijustneedtoaskusomething

Preqrequisites:
BRAIN NOT CHECK :(

Ok wel hey, I don't know much about all of this but I am not English so its all a bit hard to understand I dont really get what to do. So I coppied to script and I had to put my author there and then I paste it in console I thought someone once showed me it I forgot it already. But yea I might be doing soemthing wrong can someone help me.

@Nigel1992
Copy link

Nigel1992 commented Mar 11, 2019

If anyone needs help getting this to work for deleting Dm's, heres what worked for me.
To grab the Guild ID, simply open the DM in Chrome/Firefox.
Https://discordapp.com/channels/@me/ THIS IS YOUR GUILD ID
To grab a ID/Author ID, click on the same chat [left-side slider] and right-click "Copy ID"
Now use all this information including your Authorization token [even in Firefox] to delete the messages.

Only replace values from Lines: 74, 85.
Replace URL on line 6 with DM url [see below] and replace GUILD ID.
const searchURL = https://discordapp.com/api/v6/channels/${guild_id}/messages/search?author_id=${author_id}&include_nsfw=true

@ivmirx
Copy link

ivmirx commented Mar 27, 2019

If you want to delete messages before a specific date, do the following:

  1. Open any server to make the search field visible.
  2. Open the "Network" tab in the inspector and clean it from old requests with the trash can icon.
  3. Click in Discord's search field to show the dropdown, then click the "before" option.
  4. Select the date in the calendar.
  5. In the "Network" tab look for the request that contains ?max_id=....
  6. Click on it and copy the max_id=... part from the URL on the right.
  7. Append it to the script's request in the Line 6 by using &.

So now you should have something like:
https://discordapp.com/api/v6/guilds/${guild_id}/messages/search?author_id=${author_id}&include_nsfw=true&max_id=540727993958400000
(this example is for 2019-02-01).

@ethancedrik
Copy link

ethancedrik commented Apr 5, 2019

Hey, this is semi unrelated but let's say I have the URL of a message I sent, which can be found by right clicking a message and clicking "Copy Link"

Is there any way I can, from the Discord console, paste a script in filling in my auth token and just the URL of the message I want deleted, and have it delete the specified message?

Would someone be willing to write a quick script that could do this?

@rcx
Copy link
Author

rcx commented Apr 7, 2019

@ethancedrik

const headers = { Authorization: "your auth token goes here" }
await fetch(`https://discordapp.com/api/v6/channels/channel id goes here/messages/message id goes here`, { headers, method: 'DELETE' })

how to get the ids. anatomy of a discord message link:
https://discordapp.com/channels/guild id/channel id/message id
you can write javascript to parse out the ids to make the fetch url

@pshhhhhh
Copy link

My only suggestion to make things more clear (and require less brains of people on the internet) would be to change var authToken = "" to var authToken = "____________auth_token_here_______________" and update section 2.3 of the guide to reflect the change. Cheers for the help. Brilliant work. Thanks everyone for the helpful comments to get things working. I feel like I used your brains for my benefit!

@Nottt
Copy link

Nottt commented Apr 18, 2019

Guys I found a automated solution easier, download autohotkey, create a script like this:

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

^j::

Loop, 100
{
	send, {Up}
	send, ^a
	send, {BS}
	send, {Enter}
	send, {Enter}
	sleep, 500
}
Return

Then you can run it with ctrl + j in any discord DM/channel and your last messages will be deleted

@rcx
Copy link
Author

rcx commented Jul 22, 2019

@pshhhhhh i updated the script to include your suggestion, thanks!
@Nottt unfortunately the autohotkey solution requires Discord to be focused... it is simple though which is good!

Copy link

ghost commented Aug 17, 2019

I'm trying to use this script in a very long (300k total!) messages DM channel, and it worked very well at first, deleting many messages. I've now been stuck, every single attempt at message deletion is met with a 403 error. I'm not really a programmer, but I have two suspicions:

  • The script is getting stuck on a "XYZ started a call" message (there's a block of maybe 10 of these in a row), or
  • Discord has rate limited me after deleting thousands of messages in the span of 24 hours

Is there any merit to these guesses? If so, anything to be done? If it means anything, I've been running the script directly in the Discord windows client.
I apologize if any of this is formatted incorrectly, I'm a first time github commenter.

Edit: the user is also blocked, that may be important.

Edit 2: I'm pretty sure it was the block of calls. I found a workaround using Joecow's edits on this script:
https://gist.github.com/victornpb/135f5b346dea4decfc8f63ad7d9cc182#file-deletediscordmessages-js

I'm not sure if this will work forever- if it does, I still hope my comment can help improve this script.

@rcx
Copy link
Author

rcx commented Aug 18, 2019 via email

Copy link

ghost commented Aug 22, 2019

@ecx86 I forked your gist and wrote some code to automatically retrieve the channel type, channel ID, user ID and token. full code here
https://gist.github.com/cntVertex/2ad8a1fb1e614067afde3a08e190da3b

// original code from https://gist.github.com/ecx86/a29eac843a8ecf97a22accb34ef60b88

var clearMessages = function (target_type, guild_id, author_id, auth_token, deleted = new Set()) {
    const searchURL = `https://discordapp.com/api/v6/${target_type}/${guild_id}/messages/search?author_id=${author_id}&include_nsfw=true`
    const headers = { Authorization: auth_token }
    let clock = 0
    var interval = 500
    
    function delay(duration) {
        return new Promise((resolve) => {
            setTimeout(resolve, duration)
        })
    }
    
    function loadMessages() {
        return fetch(searchURL, { headers })
    }

    function tryDeleteMessage(message) {
        if (message.author.id == author_id && !deleted.has(message.id)) {
			console.log(`Deleting message ${message.id} from ${message.author.username} (${message.content}...)`)
            return fetch(`https://discordapp.com/api/v6/channels/${message.channel_id}/messages/${message.id}`, { headers, method: 'DELETE' })
        }
    }

    let messagesStore = []

    loadMessages()
        .then(resp => resp.json())
        .then(messages => {
            messages = messages.messages
            if (messages === undefined || messages === null || messages.length == 0) {
                console.log(`Couldn't load messages. Check guild id, author id, and auth token.`)
                return
            }

            messages = messages.filter(m => m)
            messages = [].concat.apply([], messages);
            messages = messages.filter(m => m)
            if (messages.length === 0) {
                console.log(`Couldn't load messages. Check guild id, author id, and auth token.`)
                return
            }

            messages = messages.filter(m => m.author.id == author_id)
            messages = messages.filter((e, i) => messages.findIndex(a => a.id === e.id) === i);

            messagesStore = messagesStore.concat(messages)
            return Promise.all(messagesStore.map(async message => {
                await delay(clock += interval);
                const resp = await tryDeleteMessage(message);
                if (resp) {
                    if (resp.status == 429) {
                        interval += 10;
                    }
                    else if (resp.status === 204) {
                        deleted.add(message.id);
                        return resp.text();
                    }
                }
            }))
        })
        .then(function () {
            if (messagesStore.length !== 0) {
                clearMessages(target_type, guild_id, author_id, auth_token, deleted)
            } else {
                console.log(`We have loaded all messages in this chat.`)
            }
        })
}

function beforeString(org_str, search_str = '/') {
    var n = org_str.indexOf(search_str)
    var s = org_str.substring(0, n != -1 ? n : org_str.length)
    return s;
}

function startRemove() {
    window.alert("getting token. when confirm window showed up, please click 'Cancel' in Chrome / 'Stay on Page' in Firefox.");

    window.onbeforeunload = function () {
        return false;
    }

    window.location.reload();
    
    var local_storage = document.body.appendChild(document.createElement(`iframe`)).contentWindow.localStorage
    var author_id = JSON.parse(local_storage.user_id_cache)
    var guild_id = beforeString(window.location.href.replace("https://discordapp.com/channels/", "").replace("@me/", ""))
    var target_type = window.location.href.includes("/@me/") ? "channels" : "guilds"
    var auth_token = "" // manual entry required if not automatically received

    if (auth_token.length === 0) {
        var local_token = local_storage.token
        if (local_token === undefined) {
            console.log("token cannot be retrieved automatically.")
        } else {
            auth_token = JSON.parse(local_token)
        }
    }
    if (auth_token.length !== 0) {
        console.log(target_type);
        console.log(guild_id);
        console.log(author_id);
        console.log(auth_token);
        if (confirm(`All your messages on the ${guild_id} ${(target_type == "channels" ? "DM" : "Channel")} will be deleted.`))
            clearMessages(target_type, guild_id, author_id, auth_token)
    }
}

startRemove();

this part used to disable token security measures

    window.alert("getting token. when confirm window showed up, please click 'Cancel' in Chrome / 'Stay on Page' in Firefox.");

    window.onbeforeunload = function () {
        return false;
    }

    window.location.reload();

thanks

@CanadianLegend
Copy link

I can't seem to get this to work... I'm a total newb at this lol. Would appreciate any help.
I'm particularly stuck on what to do for 'guild id' as the above suggestions aren't working for me. It would be awesome if someone could alter the code for me since im trying to mass delete DMs. Thanks.

@rcx
Copy link
Author

rcx commented Aug 25, 2019

@wutsurname you need to fill in the "____________your_auth_token_here_______________" part.

@ehabj check the FAQ for instructions on how to mass delete DMs. the guild id should be the id of the DM channel which you can get by viewing the network inspector.

@cntVertex Wow! the window.location.reload() trick is wonderful, thank you for sharing this. i will add that

@littlemower
Copy link

can anyone add me on discord to help me get this work? My discord is LittleMower#3447 Please!

@Raizen9
Copy link

Raizen9 commented Nov 23, 2019

It's not working anymore ?

@rcx
Copy link
Author

rcx commented Nov 23, 2019 via email

@Raizen9
Copy link

Raizen9 commented Nov 25, 2019

image
i get this but i still have messages on the server

@rcx
Copy link
Author

rcx commented Nov 27, 2019

I'm sorry... the script still works for me. Verify the guild id, author id, and auth token are configured properly in your copy of the script
Edit: Also I updated the script to make it easier to use, and fixed a bug grabbing the auth token on Desktop client.

@Raizen9
Copy link

Raizen9 commented Nov 28, 2019

Ok , It's working on chrome but not on brave , i'm on linux mint btw

@Unknown854
Copy link

Unknown854 commented Dec 1, 2019

Is there a way to get this to work for servers I'm no longer part of? I have the server IDs etc

@rcx
Copy link
Author

rcx commented Dec 1, 2019 via email

@sprokets101
Copy link

Hello again, I've been attempting to delete messages in a DM but it refuses to work. I've used your script successfully in the past numerous times and I also tried using victornpb's automated popup window script but every attempt gives me

"Error searching messages, API responded with status 404!
{"message":"404: Not Found","code":0}"

While your script gives me the following error:

d3beeefa39d6294d8b2a.js:53 GET https://discordapp.com/api/v6/channels/[the channel ID I'm trying to delete]/messages/search?author_id=[my author ID]&include_nsfw=true 404
(anonymous) @ d3beeefa39d6294d8b2a.js:53
loadMessages @ VM484:16
clearMessages @ VM484:27
(anonymous) @ VM484:82
d3beeefa39d6294d8b2a.js:53 Couldn't load messages. Check guild id, author id, and auth token.

Is this a temporary problem do you think, or has Discord changed something in their APIs?

Thanks!

@rcx
Copy link
Author

rcx commented Dec 16, 2019

@sprokets101

Hi, that api still works for me. Make sure you're using the right channel ID-- it's NOT the same as the USER id of the person you are trying to delete DMs for. You need the CHANNEL id of that dm.

@sprokets101
Copy link

@ec86

Hi, there seemed to be a problem with the API being down. I tried it again and it worked today, exact same script with the exact same figures.

Thanks, as ever, for maintaining this excellent tool. Happy holidays!

@Milamber59
Copy link

Hey guys. It's not working for me, i also checked every ID and the api can read messages but can't delete them (error 403)
Any idea?

**
image
**

@rcx
Copy link
Author

rcx commented Mar 23, 2020

@Milamber59 I have no idea, this script works for me this whole time.

@rcx
Copy link
Author

rcx commented Apr 4, 2020

Updated script so it works seamlessly in Discord electron client

@rcx
Copy link
Author

rcx commented Sep 14, 2020

Updated default frequency as Discord seems ever so slightly more stringent now

@rcx
Copy link
Author

rcx commented Oct 20, 2020

Updated: By default, delete by oldest first

@rcx
Copy link
Author

rcx commented Jul 19, 2021

Updated

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