In this tutorial, you'll see how you can build an app that can publish notification messages that contain interactive elements. We'll show you how apps can respond to the use of those interactive elements and use them to trigger useful flows.
Features you’ll use
Every Slack app journey begins with a few common steps. You'll need to create an app, give it some permission scopes, and then install it to a suitable development workspace.
We'll show you how to use the app config pages and give you a brief tour of all the features you can setup for your app.
You won't get far without a Slack app to accompany you on this journey. Start here by creating an app.
Scopes give your app permission to do things (for example, post messages) in Slack. They're an essential component of any functional Slack app.
Each scope that you add to your app will be presented in a permission request dialog during app installation. When you're building an app in a development workspace that you control, you'll be able to experience both sides of this system.
Each app can use lots of different scopes, with the exact list depending on the type of access token the app will use. We favour using bot tokens for most apps, so we'll explain how to request scopes for that token type.
To choose the scopes to add to your app:
Once added, the scope list will be saved automatically. Your app will now request these scopes during installation.
If you add scopes to your app config after installation, simply reinstall your app to request and grant permission for the added scopes.
To read more about scopes and permissions, check out our app authentication docs.
Your app can request any scope you want—but final say always resides with the user installing your app. A user can choose to refuse any and all installs that seem to request permissions beyond what they're comfortable granting.
When you're installing your app to your own development workspace, you can experience this process for yourself.
To install your app to your development workspace:
You'll be redirected to the OAuth permission request dialog:
As a user, you're choosing to trust the app. Is it trustworthy? Well, you're building it—hopefully, it's not too bad. After installation, you'll be redirected back to your app config. You'll see the newly generated access token on the Install App page you're redirected to.
Access tokens are imbued with power. Your app is able to use this new access token to do practically everything that a Slack app can do.
Remember to keep your access token secret and safe, to avoid violating the security of your app, and to maintain the trust of your app's users.
At a minimum, avoid checking your access token into public version control. Access it via an environment variable. We've also got plenty more best practices for app security.
Bolt is a framework that lets you build Slack apps in a flash—available in JavaScript, Python, and Java.
Bolt handles much of the foundational setup so you can focus on your app's functionality. Out of the box, Bolt includes:
Bolt also has built-in type support, so you can get more work done right from your code editor.
Follow our guides on getting started with Bolt for JavaScript, Bolt for Python, or Bolt for Java. Or dig deeper by exploring our resources and sample code.
Your Slack app can publish simple text messages to public channels or private conversations just as users can. These messages can be used as notifications for your app.
Apps can also include special visual components in their messages, using a framework we call Block Kit. Block Kit contains a subset of interactive components that allow users to take actions within your app, directly from a conversation.
Composing a notification message involves choosing blocks, and laying them out to present important data. In doing so, you’ll create an array of Block Kit objects that will be used when publishing a message.
After you've finished with this section, you will have created an interactive message payload to publish in the next section.
All of the Slack APIs that publish messages use a common structure, called a message payload.
This payload is a JSON object that is used to define the content of the message and metadata about the message. The metadata can include required information such as the conversation the message should be published to, and optional parameters which determine the visual composition of the message.
Here's a very basic app-published message payload:
{
"channel": "CONVERSATION_ID",
"text": "Hello, world.",
}
You can go further to customize published messages by using special text formatting, or by composing a blocks
parameter to define a rich, and potentially interactive, message layout.
View our message payload reference for a list of potential payload parameters.
Text within message payloads can be formatted using a special markup syntax called mrkdwn
. Consult this reference guide to learn everything you can do with mrkdwn
.
Slack provides a range of visual components, called Block Kit, that can be used in messages. These blocks can be used to lay out complex information in a way that's easy to digest.
Each block is represented in our APIs as a JSON object. Here's an example of a simple section
block:
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "New Paid Time Off request from <example.com|Fred Enriquez>\n\n<https://example.com|View request>"
}
}
Every block contains a type
field — specifying which of the available blocks to use — along with other fields that describe the content of the block.
Block Kit Builder is a visual prototyping sandbox that will let you choose from, configure, and preview all the available blocks.
If you want to skip the builder, the block reference guide contains the specifications of every block, and the JSON fields required for each of them.
Individual blocks can be stacked together to create complex visual layouts.
When you've chosen each of the blocks you want in your layout, simply place each of them in an array, in visual order, like this:
[
{
"type": "header",
"text": {
"type": "plain_text",
"text": "New request"
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Type:*\nPaid Time Off"
},
{
"type": "mrkdwn",
"text": "*Created by:*\n<example.com|Fred Enriquez>"
}
]
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*When:*\nAug 10 - Aug 13"
}
]
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "<https://example.com|View request>"
}
}
]
Block Kit Builder will allow you to drag, drop, and rearrange blocks to design and preview Block Kit layouts.
Alternatively you can use the block reference guide to manually generate a complete blocks
array, like the one shown above.
Blocks are added to messages by adding a blocks
array to the message payload, like this:
{
"channel": "C1H9RESGL",
"text": "New Paid Time Off request from Fred Enriquez",
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "New request"
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Type:*\nPaid Time Off"
},
{
"type": "mrkdwn",
"text": "*Created by:*\n<example.com|Fred Enriquez>"
}
]
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*When:*\nAug 10 - Aug 13"
}
]
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "<https://example.com|View request>"
}
}
]
}
When you're using blocks
in your message payload, the top-level text
field becomes a fallback message displayed in notifications. Blocks should define everything else about the desired visible message.
You can take Block Kit layouts further by adding interactive components like buttons, select menus, date pickers, and more.
Interactive components allow your app to retrieve, manipulate, update, and return data to external services in response to user action. All from the comfort of Slack.
Adding interactive components is no different from adding any other block. Let's add a couple of buttons to an actions block in a message payload:
{
"channel": "C1H9RESGL",
"text": "New Paid Time Off request from Fred Enriquez",
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "New request",
"emoji": true
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Type:*\nPaid Time Off"
},
{
"type": "mrkdwn",
"text": "*Created by:*\n<example.com|Fred Enriquez>"
}
]
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*When:*\nAug 10 - Aug 13"
}
]
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"emoji": true,
"text": "Approve"
},
"style": "primary",
"value": "click_me_123"
},
{
"type": "button",
"text": {
"type": "plain_text",
"emoji": true,
"text": "Reject"
},
"style": "danger",
"value": "click_me_123"
}
]
}
]
}
You could replace these buttons with any of the available interactive components. You can also add a button as a section
block's accessory
element, rather than the actions
block used above.
Browse the interactive components to see a full list of what's available, or try the Block Kit Builder tool to visually prototype a layout with interactive components.
When the message payload you've constructed here is published to Slack, people will be able to click on the buttons included in the layout. When that happens, your app will be sent interactive payloads for processing and response.
We'll show you how these interactive payloads work, and how to configure your app to receive them, in a later step.
The Web API is the core of every Slack app's functionality. In the next section, we'll use it to access the API for publishing messages.
Before we do that, familiarize yourself with the process for actually using the API. We recommend using Bolt to save yourself a lot of time and effort.
After finishing this section, you should be familiar with the basics of using the Web API in an app.
If you're using our Bolt framework, which we recommend, making Web API calls is simple. All flavours of Bolt use a similar client interface, with API parameters passed as arguments.
Here's a basic Bolt example that calls chat.postMessage
:
If you're curious, you can read more about how Bolt can be used to call the Web API—just consult the relevant Bolt for JavaScript, Bolt for Python, or Bolt for Java docs.
Not using Bolt? Read how to manually build an app that can interact with the Web API.
Putting everything you've learned so far together, you're ready to make the API calls that will publish a notification as a message.
Because you requested chat:write
and chat:write.public
permissions earlier, your app will be able to publish to any Slack conversation it is a member of or any public channel, at any time. Notification messages should typically be sent in reaction to some event on a service outside of Slack.
To publish your message, we'll use the chat.postMessage
Web API method.
After finishing this step, your app will have published an interactive notification to a Slack conversation of your choice.
When an app publishes a message, the app needs to know which Slack conversation the message should be added to.
In order to find a valid Slack conversation ID, we'll use the conversations.list
API method. This API will return a list of all public channels in the workspace your app is installed to. You'll need the channels:read
permission granted to your app.
Within that list, we'll be able to find a specific id
of the conversation that we want to access. Here's an example API call:
You'll get back a JSON object, with a channels
array containing all the public channels that your app can see. You can find your channel by looking for the name
in each object.
When you've found the matching channel, make note of the id
value, as you'll need it for certain API calls.
If your app implements shortcuts, slash commands, or uses the Events API, your app will see conversation id
s in request payloads sent by those features.
In those cases, your app can dynamically respond using the payload data to identify the relevant conversation, rather than needing to use the conversations.list
method described above.
If you're using Bolt, publishing a message is really simple. Just call chat.postMessage
as below, making sure to include your blocks
array in the message payload:
If you're not using Bolt, you'll need to manually create an API call to chat.postMessage
.
Read our detailed guide to sending messages if you want to learn more.
Your interactive notification message should now be sitting in the chosen conversation, with some buttons awaiting interaction.
When one of those buttons are used, Slack will send an interaction payload to your app. You'll use the information in that payload to spur some relevant action in your app.
After finishing this step, your app will be able to handle interactions with published notifications.
Every interaction between a user and an app exists as part of a flow, a series of events that gets something done:
In the next few steps, we'll get your app ready to handle this flow.
Interaction payloads are sent to your app's configured Request URL. To add a Request URL to your app:
If you're using Socket Mode, you won't need to configure a Request URL. Interaction payloads will instead be sent to your WebSocket URL, and will be wrapped in some Socket Mode specific metadata.
If you're using the Bolt framework, the process of receiving and processing interaction payloads is handled for you. All you need to do is create a listener for each block_id
or action_id
created by your app:
Your app has access to all the contextual info about the interaction that's included in the payload. Your app can use as much or as little of the info as needed to generate a response.
You can view a full list of the fields included in our block_actions
payload reference.
All apps must acknowledge the receipt of an interaction payload within 3 seconds. To enable this acknowledgment response, Bolt action listeners are passed a callable ack()
function (in Bolt for Java this function is ctx.ack()
).
This ack()
function requires no arguments. We recommend calling ack()
immediately, before any other processing, since you only have 3 seconds to respond.
Not using Bolt? Read how to manually build an app that can receive and process interaction payloads.
If you've reached this step, your app should be able to successfully handle user interactions. Now you need to decide what your app will do in response. Send a message to the user, pop a modal, update data on an external service, or lots of other possibilities.
Read our guide to responding to user interactions to help you decide what to do.