How to remove Ephemeral Messages

I searched high and low on how to do this and finally came across the answer.

  1. Your ephemeral message must trigger an action, i.e. button click.
  2. Your response to the action must use the following body

    {
        'response_type': 'ephemeral',
        'text': '',
        'replace_original': true,
        'delete_original': true
    }
    

'delete_original': true is the key here, which as far as I can tell is not mentioned in any of the API guides, however it is present in the API field guide under Top-level message fields

If you wish to change the response_type of your message instead of deleting it, you must do so by first deleting the ephemeral message and then posting the same message with 'response_type': 'in_channel'.

In my use case I wanted to take an ephemeral message and repost it with the exact same message body as an in-channel message. I have not found a way to retrieve the content of your ephemeral message, so the best method I've found is to pass whatever necessary data spawned your ephemeral message in the button's value so that your action handler can read this data and dynamically recreate the message body.

In my case, this was the user input being used to perform a query. On the off chance that data in the database changes between the time the original ephemeral message is posted and the in-channel version is posted they will be different. You may be able to send a JSON string directly through this value field and avoid making additional database calls and running the risk of messages changing when posted to the channel. The character limit of value is 2000 so JSON passing is extremely limited.

Assuming you use the same code to generate this body when initially creating the ephemeral message and also when recreating it in-channel, you should receive the same body and essentially are able to change an ephemeral message to in-channel message.


Some ephemeral messages can be "soft" deleted/replaced but only when posted as part of a message with interactive features like buttons or menus. When a button is clicked or a menu selection made, you have a chance to instruct Slack to either "delete" the original message, or replace it with a new one. These docs detail using responses and response_url to accomplish that.

A message created with chat.postEphemeral that itself has no interactive features can never be explicitly deleted. Once it's delivered, it's like a ghost and will disappear following a restart or refresh.

Answering your bulleted questions in order:

  • Correct, you essentially start a new chain of interactivity with net new ephemeral message you post to that user
  • Each interactive message interaction will have its own response URL. The new ephemeral message won't have a response_url you can use until the end user presses a button, selects a menu item, etc.
  • response_url will eventually expire ("using the response_url, your app can continue interacting with users up to 5 times within 30 minutes of the action invocation.") If the original message is non-ephemeral, using chat.update is a better strategy for longer timelines. With ephemeral messages, it's more of a "do your best" strategy. They'll eventually get cleaned up for the user after a refresh.
  • I think you have a good handle on what's best. Personally, I think it's easier to kick off a new "in_channel" message by using chat.postMessage instead of as a chain effect directly from a slash command or interaction.

The Kotlin/Java version for this solution using the Bolt API as shown below


import com.slack.api.bolt.handler.builtin.BlockActionHandler
import com.slack.api.bolt.request.builtin.BlockActionRequest
import com.slack.api.app_backend.interactive_components.response.ActionResponse
import com.slack.api.bolt.response.Response
import com.slack.api.bolt.context.builtin.ActionContext

object Handler : BlockActionHandler {

   override fun apply(req: BlockActionRequest,
                      context: ActionContext): Response {
            val response = ActionResponse
                                 .builder()
                                 .deleteOriginal(true)
                                 .replaceOriginal(true)
                                 .responseType("ephemeral")
                                 .blocks(listOf())
                                 .text("")
                                 .build()
            context.respond(response)
            return context.ack()
   }
}

Tags:

Slack Api