Publish interactive notifications

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

Scopes you'll request

1Before you begin

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.

  • Setting up a Slack app
    Watch our video showing how to create and setup a new Slack app.

    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.

  • Create an app

    You won't get far without a Slack app to accompany you on this journey. Start here by creating an app.

  • Requesting scopes for your 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:

    1. Head over to app config page for your app.
    2. Navigate to the OAuth & Permissions page.
    3. Scroll down to the Bot Token Scopes section.
    4. Click Add an OAuth Scope.
    5. Add the scopes listed above.

    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.

  • Install your app

    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:

    1. Head over to app config page for your app.
    2. Navigate to the Install App page.
    3. Click Install to Workspace.

    You'll be redirected to the OAuth permission request dialog:

    Oauth UI for users

    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.

  • Use Bolt to build your app

    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:

    • A basic web server to run your app on
    • Authentication and installation handling for all the ins and outs of OAuth
    • Simplified interfaces for all Slack APIs and app features
    • Automatic token validation, retry, and rate-limiting logic

    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.

2Compose your interactive notification

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.

When you're done

After you've finished with this section, you will have created an interactive message payload to publish in the next section.

  • Create a basic message payload

    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.

  • OptionalFormat text in your message

    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.

  • Add a rich layout to your message using Block Kit

    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.

    Define a single block

    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>"
      }
    }
    

    Preview

    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.

    Stacking multiple blocks

    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>"
    		}
    	}
    ]
    

    Preview

    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.

    Add blocks to your message payload

    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.

  • Add interactive blocks to your 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"
    				}
    			]
    		}
    	]
    }
    

    Preview

    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.

3Learn how to use the Web API

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.

When you're done

After finishing this section, you should be familiar with the basics of using the Web API in an app.

  • Using the Slack Web API with Bolt

    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:

    Calling chat.postMessage in JavaScript

    Show code to initialize app
    // ID of the channel you want to send the message to const channelId = "C12345"; try { // Call the chat.postMessage method using the WebClient const result = await client.chat.postMessage({ channel: channelId, text: "Hello world" }); console.log(result); } catch (error) { console.error(error); }

    New to building Slack apps with JavaScript? Read Getting Started with Bolt for Javascript.

    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.

  • AlternativeUse the Web API manually

    Not using Bolt? Read how to manually build an app that can interact with the Web API.

4Publish your interactive notification

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.

When you're done

After finishing this step, your app will have published an interactive notification to a Slack conversation of your choice.

  • Find a place to publish your message

    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:

    Finding a conversation in HTTP

    GET https://slack.com/api/conversations.list
    Authorization: Bearer xoxb-your-token

    Explore our developer tools to simplify your app development.

    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 ids 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.

  • Publish your message with Bolt

    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:

    Calling chat.postMessage in JavaScript

    Show code to initialize app
    // ID of the channel you want to send the message to const channelId = "C12345"; try { // Call the chat.postMessage method using the WebClient const result = await client.chat.postMessage({ channel: channelId, text: "Hello world" }); console.log(result); } catch (error) { console.error(error); }

    New to building Slack apps with JavaScript? Read Getting Started with Bolt for Javascript.

  • AlternativePublish your message manually

    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.

5Prepare your app for interactions

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.

When you're done

After finishing this step, your app will be able to handle interactions with published notifications.

  • A brief overview of interaction flow

    Every interaction between a user and an app exists as part of a flow, a series of events that gets something done:

    A user triggers an app interaction by using an interactive Block Kit component, or a shortcut, or a Slash Command.

    An interaction payload is sent to the app, which correctly receives and processes it.

    Using the context in the interaction payload, the app responds to the interaction.

    In the next few steps, we'll get your app ready to handle this flow.

  • Configure a Request URL

    Interaction payloads are sent to your app's configured Request URL. To add a Request URL to your app:

    1. Head over to app config page for your app.
    2. Navigate to the Interactivity & Shortcuts page.
    3. If you haven't already, switch on the Interactivity toggle.
    4. Add your Request URL.
    5. Click Save Changes at the bottom of the page.

    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.

  • Receive interaction payloads with Bolt

    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:

    Capturing block actions in JavaScript

    // This listener will be called every time an interactive component with the `action_id` "approve_button" is triggered
    // `block_id` is disregarded in this case
    app.action('approve_button', async ({ ack, say }) => {
    	await ack();
    	// Do something in response
    });
    
    // This listener will only be called when the `action_id` matches 'select_user' AND the `block_id` matches 'assign_ticket'
    app.action({
    	action_id: 'select_user',
    	block_id: 'assign_ticket'
    	}, async ({ body, action, ack, client }) => {
    	await ack();
    	// Do something in response
    });
    

    New to building Slack apps with JavaScript? Read Getting Started with Bolt for Javascript.

    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.

    Send an acknowledgment response

    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.

  • AlternativeReceive interaction payloads manually

    Not using Bolt? Read how to manually build an app that can receive and process interaction payloads.

  • OptionalRespond to an interaction

    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.