#!/usr/bin/env node | |
// Channel ID is on the the browser URL.: https://mycompany.slack.com/messages/MYCHANNELID/ | |
// Pass it as a parameter: node ./delete-slack-messages.js CHANNEL_ID | |
// CONFIGURATION ####################################################################################################### | |
const token = 'SLACK TOKEN'; | |
// Legacy tokens are no more supported. | |
// Please create an app or use an existing Slack App | |
// Add following scopes in your app from "OAuth & Permissions" | |
// - channels:history | |
// - groups:history | |
// - im:history | |
// - mpim:history | |
// - chat:write | |
// VALIDATION ########################################################################################################## | |
if (token === 'SLACK TOKEN') { | |
console.error('Token seems incorrect. Please open the file with an editor and modify the token variable.'); | |
} | |
let channel = ''; | |
if (process.argv[0].indexOf('node') !== -1 && process.argv.length > 2) { | |
channel = process.argv[2]; | |
} else if (process.argv.length > 1) { | |
channel = process.argv[1]; | |
} else { | |
console.log('Usage: node ./delete-slack-messages.js CHANNEL_ID'); | |
process.exit(1); | |
} | |
// GLOBALS ############################################################################################################# | |
const https = require('https') | |
const historyApiUrl = `/api/conversations.history?channel=${channel}&count=1000&cursor=`; | |
const deleteApiUrl = '/api/chat.delete'; | |
const repliesApiUrl = `/api/conversations.replies?channel=${channel}&ts=` | |
let delay = 300; // Delay between delete operations in milliseconds | |
// --------------------------------------------------------------------------------------------------------------------- | |
const sleep = delay => new Promise(r => setTimeout(r, delay)); | |
const request = (path, data) => new Promise((resolve, reject) => { | |
const options = { | |
hostname: 'slack.com', | |
port : 443, | |
path : path, | |
method : data ? 'POST' : 'GET', | |
headers : { | |
'Authorization': `Bearer ${token}`, | |
'Content-Type' : 'application/json', | |
'Accept' : 'application/json' | |
} | |
}; | |
const req = https.request(options, res => { | |
let body = ''; | |
res.on('data', chunk => (body += chunk)); | |
res.on('end', () => resolve(JSON.parse(body))); | |
}); | |
req.on('error', reject); | |
if (data) { | |
req.write(JSON.stringify(data)); | |
} | |
req.end(); | |
}); | |
// --------------------------------------------------------------------------------------------------------------------- | |
async function deleteMessages(threadTs, messages) { | |
if (messages.length == 0) { | |
return; | |
} | |
const message = messages.shift(); | |
if (message.thread_ts !== threadTs) { | |
await fetchAndDeleteMessages(message.thread_ts, ''); // Fetching replies, it will delete main message as well. | |
} else { | |
const response = await request(deleteApiUrl, {channel: channel, ts: message.ts}); | |
if (response.ok === true) { | |
console.log(message.ts + (threadTs ? ' reply' : '') + ' deleted!'); | |
} else if (response.ok === false) { | |
console.log('vada', response); | |
console.log(message.ts + ' could not be deleted! (' + response.error + ')'); | |
if (response.error === 'ratelimited') { | |
await sleep(1000); | |
delay += 100; // If rate limited error caught then we need to increase delay. | |
messages.unshift(message); | |
} | |
} | |
} | |
await sleep(delay); | |
await deleteMessages(threadTs, messages); | |
} | |
// --------------------------------------------------------------------------------------------------------------------- | |
async function fetchAndDeleteMessages(threadTs, cursor) { | |
const response = await request((threadTs ? repliesApiUrl + threadTs + '&cursor=' : historyApiUrl) + cursor); | |
if (!response.ok) { | |
console.error(response.error); | |
return; | |
} | |
if (!response.messages || response.messages.length === 0) { | |
return; | |
} | |
await deleteMessages(threadTs, response.messages); | |
if (response.has_more) { | |
await fetchAndDeleteMessages(threadTs, response.response_metadata.next_cursor); | |
} | |
} | |
// --------------------------------------------------------------------------------------------------------------------- | |
fetchAndDeleteMessages(null, ''); |
This comment has been minimized.
This comment has been minimized.
would it be possible to remove DMs, too? |
This comment has been minimized.
This comment has been minimized.
Code deletes the messages but when I come back they are there again. Any ideas? |
This comment has been minimized.
This comment has been minimized.
Thank you so much!! Exactly what i needed. I modified the code a bit to delete direct messages and continue deleting after 1000 limit. If anyone is interested: |
This comment has been minimized.
This comment has been minimized.
thanks man. works like a charm |
This comment has been minimized.
This comment has been minimized.
Hi there! I'm a bit of a noob when it comes to APIs and in need of a bit of help.. Do I understand correctly that in order to wipe my message history in my #general, I: 1) modify the raw code; 2) DL it as a .zip file; 3) import it to my Slack? If so, what are the fields I need to modify in the raw code and how can I find my #general channel ID? TY |
This comment has been minimized.
This comment has been minimized.
Hi @niiongi, follow this post: https://medium.com/@jjerryhan/cleaning-all-messages-on-slack-channel-c46d71615c9a |
This comment has been minimized.
This comment has been minimized.
@woodyb23 (and others) Slack imposes an API request limit of 1 per second (https://api.slack.com/docs/rate-limits#web). Short bursts are allowed, but once you hit 20 messages or so, requests will start getting rejected. Modify the settings of this script to use a delay of say 1250ms so you won't hit the rate limit and messages will be deleted properly. |
This comment has been minimized.
This comment has been minimized.
Thank you very much~! I modified the code a bit, also added promise methods, delete all messages, and delete direct message. :) |
This comment has been minimized.
This comment has been minimized.
Having issues when using it for 1-on-1 Chat, can't get around this:
BUMP** Can't figure out why but it seems cannot delete chats, just general group chats. EDIT: Basically, they are forcing you to pay. |
This comment has been minimized.
This comment has been minimized.
Now, It supports chat messages as well. And automatically proceed to the next 1000 messages. |
This comment has been minimized.
This comment has been minimized.
Not working |
This comment has been minimized.
This comment has been minimized.
super neat ! thank you ! |
This comment has been minimized.
This comment has been minimized.
Works perfectly! |
This comment has been minimized.
This comment has been minimized.
Thank you for sharing. I had a dream where hubot had this functionality in coffee script! KUDOS! |
This comment has been minimized.
This comment has been minimized.
Very Tanks :) |
This comment has been minimized.
This comment has been minimized.
|
This comment has been minimized.
This comment has been minimized.
Pretty cool. I would suggest to keep a count, help know where things at |
This comment has been minimized.
This comment has been minimized.
The script is not warning about errors. I've made a little modification to it in line 93 so it will throw errors if there's any: // check if response is ok
if (response.ok) {
if (response.messages && response.messages.length > 0) {
if (response.has_more) {
nextCursor = response.response_metadata.next_cursor;
}
for (let i = 0; i < response.messages.length; i++) {
messages.push(response.messages[i].ts);
}
deleteMessage();
}
} else {
throw new Error(response.error)
} |
This comment has been minimized.
This comment has been minimized.
Good job. Thanks! |
This comment has been minimized.
This comment has been minimized.
When not using legacy tokens, need to create a Slack App with the scopes:
|
This comment has been minimized.
This comment has been minimized.
I would suggest to use |
This comment has been minimized.
This comment has been minimized.
Thanks for the suggestion. But seems it's a basic queue mechanism. First in First out. That's why we use shift-push. shift-unshift is more like a stack. |
This comment has been minimized.
This comment has been minimized.
Sorry my bad, You're right. In case of failure, it should be the first one to be tried. |
This comment has been minimized.
This comment has been minimized.
It works like a charm! But, for example, it will be more efficient if the code only tries to delete the own messages.
Thank you for code! :D |
This comment has been minimized.
This comment has been minimized.
Thanks, It might be optional. I guess. It's better to convert this to a complete project instead of simple gist script. |
This comment has been minimized.
This comment has been minimized.
Thank for the code @firatkucuk I just updated the code with ES6, and it also accept token as parameter. Hope you have time to check it out https://gist.github.com/Toanzzz/0bc9f903207a6cd4d51ada76edd45513 |
This comment has been minimized.
This comment has been minimized.
Thanks, seems way clearer. |
This comment has been minimized.
This comment has been minimized.
This works like a charm! Thanks for doing this and sharing with the public! |
This comment has been minimized.
This comment has been minimized.
This is a great app so far - thank you so much! Is there a way to delete threaded messages and DM conversations too? (I can currently only delete DM's that I've sent myself, I would like to flush everyone's messages throughout the entire slack workspace regardless if I was in the conversation or not) |
This comment has been minimized.
This comment has been minimized.
Thanks for your good wishes, |
This comment has been minimized.
This comment has been minimized.
Worked like a charm! A bit more tracing would be great tho :) |
This comment has been minimized.
This comment has been minimized.
I've updated my fork version too, it is fully interactive, no need to update file content if desired. Here's the link if anyone needs: :) |
This comment has been minimized.
This comment has been minimized.
Worked like a charm, thank you I also created a fork to delete thread replies |
This comment has been minimized.
This comment has been minimized.
It's amazing. Thank you so much. :-) |
This comment has been minimized.
This comment has been minimized.
@aldidoanta I'm using your script but thread replies don't work.. is there anything I need to know/do to make it work? |
This comment has been minimized.
This comment has been minimized.
Gonna update my script for thread replies soon. |
This comment has been minimized.
This comment has been minimized.
Any error messages? Or it just didn't work? EDIT It looks like the API response has changed. I'll take a look at my gist later. |
This comment has been minimized.
This comment has been minimized.
I updated the script so you can delete thread replies as well. Thanks @Toanzzz for ES6 conversion. |
This comment has been minimized.
This comment has been minimized.
this works perfectly, is there a way to stop the script once all messages have been deleted withing the script as apposed to manually stopping it |
This comment has been minimized.
This comment has been minimized.
@z33ma there should be something wrong. 'cause it automatically stops after execution. |
This comment has been minimized.
This comment has been minimized.
Hi yes sorry I didn't give it enough time, working correctly thank you :) quick question, is there a way to delete X amount of messages by changing (messages.length == 0) ? |
This comment has been minimized.
This comment has been minimized.
@z33ma no it checks the queue size, it's better to use a script-wide counter for this purpose. |
This comment has been minimized.
This comment has been minimized.
@Ausaes, where did you put that line of code within the script? It sure is wasting a ton of time trying to delete messages that I don't have permission to delete. And I tried putting your line of code in multiple different places within the script but it threw some kind of error or another each time I ran it. |
This comment has been minimized.
This comment has been minimized.
Hello, after bit of struggle i am able to run the node command but it says |
This comment has been minimized.
This comment has been minimized.
You can right click the channel on slack and copy the link it's in the channel url. |
This comment has been minimized.
This comment has been minimized.
Hello, yes i sorted it out, pls check updated msg.... it is not able to delete any msg... :'( |
This comment has been minimized.
This comment has been minimized.
That means you don't have permission to delete that message. If you're not "owne"r you can only delete your own messages. |
This comment has been minimized.
This comment has been minimized.
Hello, thanks for the quick response.
and after few hours, it ended with some thread error. |
This comment has been minimized.
This comment has been minimized.
so no succeeded deletion? That's weird. I just try it works fine. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
@firatkucuk thanks, now it is working) As parameter I use last part(second_code) of url: https://app.slack.com/client/first_code/second_code |
This comment has been minimized.
This comment has been minimized.
it should be channel id |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
seems a token issue then: |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
I originally created a new test team with three channels and two users. And yes I can delete messages manually. |
This comment has been minimized.
This comment has been minimized.
I found the solution! |
This comment has been minimized.
This comment has been minimized.
Hey guys, which "token" exactly am I supposed to use here? |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
TBH, it should work with those settings could you please add those bot scopes as well: |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
@kadiiskiFFW No problem. I'll try to create an app from scratch in my spare time. It was old-style tokens and was really easy to use then slack changed to tokens with scopes. Now it's really hard to adjust things. |
This comment has been minimized.
This comment has been minimized.
@firatkucuk thank you very much for the effort! |
This comment has been minimized.
This comment has been minimized.
FWIW, this was not working for me too but i gave up because it is not that important for me. thanks. |
This comment has been minimized.
This comment has been minimized.
I have created a clone app that is identical to the working one and seems there's an issue on the slack side. I have contacted slack support. |
This comment has been minimized.
This comment has been minimized.
@kadiiskiFFW and @lorvent for the new application they are no longer support tokens from query string so I've updated the code using as |
This comment has been minimized.
Nice code