These docs describe an outmoded approach to composing messages and interactive experiences. Learn how to more effectively communicate and help folks get work done by our new documentation and transitioning to "blocks".

Legacy: Interactive messages.

Conversation is central to the chat experience, but messages do more than just communicate. Made interactive, messages inspire decisive, calculated action all from the comfort of Slack.

Provide users with direct paths to goals with message buttons:

An approval workflow powered by message buttons

Give them the ability to do something with a message via a message shortcut:

Once installed, your app's message shortcuts appear in the More actions section of each Slack message's context menu, beside the default actions.

Or let users navigate through more nuanced options with message menus:

Triforce Project PM

The interactive message framework

Interactive messages are much like other messages, only they contain buttons, a variety of menus types, or they have some custom message shortcuts available. Rather than remaining mostly static, interactive messages evolve over time.

Message buttons and menus may travel almost anywhere a message goes.

Attach them:

Message shortcuts are available on any message, except for those spooky, ghostly ephemeral messages and the best thing is they haunt appear without needing any initial action, unlike buttons or menus.

Yes, interactive messages work on Enterprise Grid and on internal integrations built for your workspace. A Slack app is required.

Lifecycle of a typical interactive message flow

Whether using buttons, message shortcuts, or menus, interactive messages flow like so:

  1. A message exists, ready for action. If your app created it, it might have buttons, or it might have menus, and if it's not ephemeral it might have custom message shortcuts available. Now all the users who can read it can interact with it.

  2. Users encounter your message and, inspired by its call to action, clicks or makes a selection. This triggers an invocation of your application's associated Request URL.

  3. Slack sends a request to your Request URL, sending all the context needed to identify the originating message, the user executing the action, and the specific values you've associated with the action. This request also contains a response_url you can use to continue interacting with the user or channel.

  4. Your app responds to the action. If responding directly to the incoming invocation request, your provided message will replace the existing message. Or respond with an ephemeral message, visible only to the invoking user. Or respond with just HTTP 200 OK and delay continuing the interaction until later using the provided response_url. There are many ways for your app to respond.

  5. Meanwhile: Your application does whatever it does as a result of the intended action to be taken: enqueue a process, save a database row or some prince or princess captured in a castle. All the while your app may continue interacting with users through additional messages and evolving shortcuts.

  6. By using the response_url, your app can continue interacting with users up to 5 times within 30 minutes of the action invocation. Use this to continue through a workflow until it is complete.

  7. Messages can evolve. By using chat.update and your created message's message_ts field, you can modify the original interactive message (including all of its attachments) to add or remove buttons or menus based on user interactions.

With many users interacting with many messages, this lifecycle repeats itself with all its various decisions and destinations.

Messages are truly a garden of forking paths.

Interaction types

While this document covers common aspects of working with both message menus and message buttons, you'll find even more nuance and detail in each action type's dedicated documentation:

  • Message buttons are brief, decisive, and compelling decision-making aids. We recommend starting with buttons if you're new to interactive messages.
  • Message menus allow more studied conclusions to be drawn with dynamic, purpose-driven drop downs.
  • Message shortcuts are visual ways of interacting with and acting on messages - they're always available once created, no matter whether your app created the initial message or not.

Readying your application for interactive messages

Posting messages with buttons requires creating a Slack app. Create an app if you don't already have one.

Preparing your Request URL

Navigate to your application management tool and find your app's Interactive Components section.

A screenshot of the sidebar where you find this dialog

Here you'll find a interface for setting your Request URL.

A screenshot of the message actions configuration dialog

You can only configure one Request URL for your application. It will receive actions from all clicks happening throughout messages with buttons your app has produced, across all channels and workspaces. It's a master dispatch station of interactivity. If you're familiar with slash commands, you'll find it behaves very similarly.

In some ways, you're building a guided API on your servers for responding to interactive messages.

See Responding to message actions later in this doc for more detail on how to process these requests.

Request URL SSL certificate requirements

Request URLs must point to a TLS-enabled HTTPS URL located on a publicly accessible server with a valid SSL certificate.

This testing tool can help you understand whether your HTTPS implementation is valid and publicly accessible.

Don't have a SSL certificate yet? Consider using these low-cost providers:

Many find a HTTP proxying tool like ngrok useful while developing their app. This tutorial outlines getting started with ngrok.

Asking for the appropriate scopes

To post messages with buttons and process their interactions, your app just needs to be capable of posting messages. If you have a bot user integration, your bot user already has permission to create messages.

Otherwise, you'll need to request OAuth permission scopes involved with posting messages:

  • incoming-webhook (if you're sending messages via incoming webhooks)
  • commands (if you're using message shortcuts or slash commands)
  • chat:write:user (if you're sending interactive messages on behalf of users)
  • chat:write:bot (if you're sending interactive messages on behalf of a bot identity)

Building workflows

Work may be a four letter word but workflow is eight. They make work great.

Interactive messages simplify multi-step processes requiring guided user input. Straightforward yes/no/maybe so, either/or/or/or decisions? Throw them a button or two. Do users need to choose from a litany of refined choices? Let them order from a message menu.

Each interaction moves a workflow toward completion.

Posting interactive messages

There are many ways to post messages on Slack. Most of them support interactive messages like little attached riders in the conversation storm.

Most interactive messages begin their lives posted using chat.postMessage, chat.postEphemeral, or incoming webhooks. Perhaps they are notifications, or messages from a readily helpful bot user.

Some messages are made interactive, such as when elements are attached to messages mentioning watched link domains with app unfurl's chat.unfurl method.

Many interactive messages initiate through interaction itself — in response to a user-executed slash command or yet another interaction with a different or even the same (!!) interactive message.

The commonality is that your interactive messages must be posted from a Slack app.

Using chat.postMessage, chat.postEphemeral, chat.update, and chat.unfurl

There's a quirk when posting message attachments, including buttons and menus, to our Web API methods. Whether you're posting a message with chat.postMessage or chat.postEphemeral, adding attachments to a link-bearing message with chat.unfurl, or replacing them with chat.update — they all only understand application/x-www-form-urlencoded parameters. But if you're sending messages with response_url or in direct response to an invocation or with an incoming webhook, messages are posted purely as application/json.

The way out is somewhat confusing but fully functional: chat.update, chat.postMessage, and chat.postEphemeral support an attachments parameter that actually expects a URL-encoded string representation of a JSON array of attachments. Say that five times fast, blur your eyes, and apply the same philosophy to the unfurls parameter in chat.unfurl.

To send an array with a single attachment with a single action like this:

[
    {
        "callback_id": "tender_button",
        "attachment_type": "default",
        "actions": [
            {
                "name": "press",
                "text": "Press",
                "type": "button",
                "value": "pressed"
            }
        ]
    }
]

You'll need to stringify (and optionally minify) and URL-encode it into a POST or URL parameter more like:

%5B%7B%22callback_id%22%3A%22tender_button%22%2C%22attachment_type%22%3A%22default%22%2C%22actions%22%3A%5B%7B%22name%22%3A%22press%22%2C%22text%22%3A%22Press%22%2C%22type%22%3A%22button%22%2C%22value%22%3A%22pressed%22%7D%5D%7D%5D

Check out the callback_id that identifies the button in this example. All interactive messages with buttons require a callback_id. Slack uses them to show your app which button a user interacted with.

If working with a well-supported client library or framework, these details are likely blissfully hidden from you.

Receiving action invocations

When users interact with buttons or menus provided by your app or click on an action associated with your app, you'll receive an action invocation at the Request URL you registered when configuring your Slack app.

There are many ways to respond to this action, but before you do anything you'll want to verify the request in fact came from Slack.

Validating Slack requests

Important! Your Slack application panel contains a Signing Secret used for interactive messages and slash commands. You'll find it in the App Credentials section of your app's Basic Information page.

Admin page with signing secret and verification token

When your Request URL is pinged, validate the x-slack-signature header value you receive. If it does not match the signature you compute, do not respond to the request with a 200 OK or other message.

Checking the action type

Action payloads include a type field, allowing you to determine whether the invoked action originates from an interactive_message or other interactive component, like dialogs.

Here's an example of a parsed payload dispatched when users select an item from message menus:

{
  "type": "interactive_message",
  "actions": [
    {
      "name": "channel_list",
      "type": "select",
      "selected_options":[
        {
          "value": "C24BTKDQW"
        }
      ]
    }
  ],
  "callback_id": "pick_channel_for_fun",
  "team": {
    "id": "T1ABCD2E12",
    "domain": "hooli-hq"
  },
  "channel": {
    "id": "C123ABC456",
    "name": "triage-random"
  },
  "user": {
    "id": "U123ABC456",
    "name": "sbutterfield"
  },
  "action_ts": "1520966872.245369",
  "message_ts": "1520965348.000538",
  "attachment_id": "1",
  "token": "lbAZE0ckwoSNJcsGWE7sqX5j",
  "is_app_unfurl": false,
  "original_message": {
    "text": "",
    "username": "Belson Bot",
    "bot_id": "B9DKHFZ1E",
    "attachments":[
      {
        "callback_id": "pick_channel_for_fun",
        "text": "Choose a channel",
        "id": 1,
        "color": "2b72cb",
        "actions": [
          {
            "id": "1",
            "name": "channel_list",
            "text": "Public channels",
            "type": "select",
            "data_source": "channels"
          }
        ],
        "fallback":"Choose a channel"
      }
    ],
    "type": "message",
    "subtype": "bot_message",
    "ts": "1520965348.000538"
  },
  "response_url": "https://hooks.slack.com/actions/T1ABCD2E12/330361579271/0dAEyLY19ofpLwxqozy3firz",
  "trigger_id": "328654886736.72393107734.9a0f78bccc3c64093f4b12fe82ccd51e"
}

Now that that's out of the way, it's time to respond to the action.

Responding to message actions

There are several different ways to respond and each may be used in combination together for richer interactions.

When creating new messages or modifying old ones, consult the message field guide to understand how to construct all the available options.

Responding immediately

Respond to the request we send to your Request URL with a JSON message body directly.

You must respond within 3 seconds. If it takes your application longer to process the request, we recommend responding with a HTTP 200 OK immediately, then use the response_url to respond five times within thirty minutes.

Responding immediately with a JSON message body will replace the current message in its entirety by default. If you explicitly indicate that you want to create a new message instead, specify a literal false in the replace_original field.

Responding incrementally with response_url

Use the response URL provided in the post to:

  • Replace the current message
  • Respond with a public message in the channel
  • Respond with an ephemeral message in the channel that only the acting user will see

You'll be able to use a response_url five times within 30 minutes. After that, it's best to move on to new messages and new interactions.

Using chat.update to modify the original message

If you created your message using chat.postMessage, you can modify the original message with chat.update by providing the message_ts value from the original message.

We helpfully provide the original message in the original_message field of your Request URL invocation. The original_message is not provided for ephemeral messages. Bot users can modify their messages too!

Interactive messages produced by apps using chat.update can continue updating messages beyond any time window restrictions imposed on human members.

Responding with an error message

If you would like to let a user know when something goes wrong, return an ephemeral response containing a helpful error message. To do this, either respond directly to the action request, or use the provided response_url.

You'll want to send a JSON payload that looks something like this:

{
  "response_type": "ephemeral",
  "replace_original": false,
  "text": "Sorry, that didn't work. Please try again."
}

This sets your response as ephemeral, neglects to replace the original (since you don't want to spill the beans on your sidebar dialog to everyone else in the channel), and sets the text to display to the user.

Replacing the original message

By replacing the original message, you can incrementally change that message's content to reflect the actions taken by members. By adding additional interactive messages, you can refine dialog options with users, either by broadcasting to the whole channel or focusing on particular users who've invoked actions via ephemeral messages.

As you replace messages using chat.update or the replace_original option, you cannot change a message's type from ephemeral to in_channel. Once a message has been issued, it will retain its visibility quality for life.

Since your interactive messages can respond or evolve with additional content and message buttons, this cycle between creating messages, processing responses, and replacing and generating new messages is potentially endless.

Be sure and review those interactive message guidelines.

Determining user identity against your service

If your service or application needs to associate a Slack member with a specific account within your product, you'll want to unobtrusively link their account to complete the action.

When your Request URL is triggered, you'll receive the user ID and team ID for the invoker. If they do not yet exist in your system, send them an ephemeral message containing a link they can follow to link accounts on your website.

This is a great opportunity to identify users with Sign in with Slack.

Review our guidelines

Field guide

While interactive messages are built on top of typical messages, the workflow may involve many stages, with evolving request and response structures.

If you use chat.postMessage or chat.postEphemeral to send interactive messages, you'll need to handle presenting your message attachments as a JSON string placed within an application/x-www-form-urlencoded request parameter while also balancing using straight-forward application/json when working with response URLs.

For a comprehensive accounting of all the fields related to interactive messages, please consult the dedicated field guide.

Guidelines and best practices

Crafting the ideal message is never easy. Adding interactive flows and additional content while maintaining a productive flow of conversation is even harder!

We've put together a collection of best practices and guidelines to help you build the most effective and unobtrusive messages.

Here are some quick highlights:

  • Though messages may contain up to 20 attachments, messages containing buttons or menus shouldn't have more than one or two attachments.
  • Each attachment can contain up to 5 message actions, but it's best to keep options limited and decisive.
  • Use confirmation dialogs, colors, and differentiated button types (primary and danger) sparingly.
  • Message action buttons, menus, and confirmation dialogs may not contain Slack's formatting markup.

Glossary

  • Message Button: A user interface for invoking Attachment Actions. Buttons can be added, removed, changed, and clicked. Clicking a button triggers its associated Attachment Action.
  • Message Action: A user interface for invoking an app's custom Actions. Actions are added to all non-ephemeral messages posted in channels that the app is installed in.
  • Message Menu: Another user interface for invoking Attachment Actions. With message menus, a single action may hold many different values for the user to select from. The selection can be pre-populated, dynamically-driven, or you can use a custom type letting you easily utilize user and channel pickers.
  • Interactive Message: Mutable messages appearing in Slack, providing users with message buttons that applications may respond to and modify.
  • Attachments: Message Attachments are contained within messages, and typically offer a means to include rich formatting in messages, such as images, color, and lightweight key/value pairs. They may also contain Attachment Actions.
  • Attachment Actions: Objectives a member may interact with within a Message Attachment, executing an Request URL. The user will see a message button. The result of an invocation may change something in the calculus universe, and if desired, within the parent interactive message.
  • Request URL: URLs associated with your application to complete specific attachment actions. Slack will use this URL when members click buttons that trigger Attachment Actions.
  • External Suggestions URL: URLs associated with your app for dynamically populating message menus with customized options.
Recommended reading
You'll need a sandbox
Join our developer program and experiment with self-serve enterprise grid sandboxes.