Go to Slack

Enabling interactions with bots

Enable conversations between users and apps in Slack by building bots.

A conversation between @celeste and @officebot


What are bots?

A bot is a type of Slack App designed to interact with users via conversation.

A bot is the same as a regular app: it can access the same range of APIs and do all of the magical things that a Slack App can do.

But when you build a bot for your Slack App, you're giving that app a face, a name, and a personality, and encouraging users to talk to it.

Your bot can send DMs, it can be mentioned by users, it can post messages or upload files, and it can be invited to channels - or kicked out.

Bots are not cybernetic infiltration units, and it is unlikely that they dream of electric sheep, though we can't rule it out. šŸ¤–


Getting Started

Since your bot is capable of doing everything that a Slack App can do, we're going to limit our focus to a common use-case for bots. The following steps will get you to the point where you have a bot waiting for messages with trigger words and sending simple responses.

From there, you can start bolting on whatever kind of amazing app logic or nuclear-powered jet-packs you can imagine.

Before you start, you'll need a Slack App. If you don't already have one, click the following button to create it:

Create your Slack app

That done, you're all ready to arrange the architecture of this automaton.

1. Creating a bot user

To use your Slack App as a bot, first you'll need to create a Bot User for it.

Head to your app's settings page and click the Bot Users feature in the navigation menu.

You'll be presented with a button marked Add a Bot User, and when you click on it, you'll see a screen where you can configure your app's bot user with the following info:

  • Display name - the name that is displayed to other users when the bot posts messages, or the bot's profile is viewed, etc.
  • Default username - the string that is used when the bot is mentioned in a message. This username may be modified slightly from the default when it is installed to a workspace where that username is already reserved. This modification is an incrementing number appended to the username - so @username might become @username2.
  • Always Show My Bot as Online - we recommend you enable this feature, so that your bot always appears to be ready to receive input (which it probably will be). When disabled, you'll have to programmatically set its online presence.

Once you've completed these fields, click the Add Bot User button and then Save Changes.

Great, you've just created a bouncing baby bot! Don't leave the app settings yet though, there's just one more bit of configuration left to do.

2. Setting up the Events API

The Events API is a bot's equivalent of eyes and ears. It gives a bot a way to react to posted messages, changes to channels, and other activities that happen in Slack. When these events happen, a data payload will be sent to your bot, and it can use that data to form a useful response.

Giving your bot access to the Events API is pretty simple:

  • From your app's settings, click the Event Subscriptions feature in the navigation menu.
  • Switch the Enable Events toggle to on and you'll be presented with a new screen of options.
  • You'll need to configure the Request URL that the data payloads will be pushed to. This URL needs to be verified first, as outlined in the Events API docs.
  • Then you'll add some individual event subscriptions. For our bot, we're interested in the Bot Events, so click on the Add Bot User Event button.
  • There are lots of different event types you could add, but for the purposes of our tutorial let's add two event subscriptions - app_mention which sends events when someone mentions your bot, and message.channels which sends events when a new message is posted in a public channel.
  • Click the Save Changes buttons

Good news! Your bot is looking more and more life-like, and now it's ready to find a home.

3. Installing the bot to a workspace

A bot user is added to a workspace by installing the app that the bot is associated with. Once you do, you'll get a bot token that is imbued with the bot scope. This token can be used with a subset of Web API methods that we'll discuss later.

If you had already installed your app in the past, you'll need to reinstall to grant the additional bot scope. The process is the same either way:

  • On your app's settings page again, click the Install App settings item in the navigation menu.
  • On this page, click a button marked Install App to your Workspace. If you had already installed your app, the button to click will instead be marked Reinstall App.
  • You'll see a permissions authorization page, where you should click Authorize. Your app is now installed to that workspace, but you still need to invite it into individual channels.
  • You should also invite the bot to a public channel somewhere in your workspace.

Once installed, you will have generated a bot token that you should store for use later on - you can find it in your app's settings under Install App > Bot User OAuth Access Token.

Bot tokens can also be generated using the OAuth install flow if you are distributing your app beyond your own workspace.

Your bot should now be happily dwelling in the channel picked during the install process. It will be listening out for users posting in that channel, and for posted messages that mention the bot. Now you need to tell it what to do when it hears something.

4. Handling events

In a previous step, we configured the event subscriptions for your app, but now we have to actually do something with the data that will be sent with each event.

Let's imagine a simple conversational bot that responds to being mentioned by sending a couple of follow up messages:

Example conversation between a user and a bot with the user asking the bot to tell a joke

There are 4 events triggered in this conversation: the first is an app_mention event from the first message that mentions the bot; the next three are message events for each of the messages posted by Johnny.

Our bot will need to be able to interpret each event and respond accordingly.

We've avoided showing you any specific code up until now, but in the following steps we're going to explain the process and then show very simplified Express/Node.js examples of what your app logic should look like. These examples translate readily into most modern programming languages.

Receiving events

The first thing we need to do is create some app code that will correctly receive the events.

Each event will trigger a request, containing a JSON payload, sent to your configured Request URL. The Events API docs contain a full description of the shape of this JSON, and the reference for app_mention and the message.channels contain any details specific to each event type.

Your app has to be able to receive and parse this JSON, and then send an immediate confirmation response to each event request, as described in the Events API docs.

Here's how we might build our code for receiving events:

// Receive event payload to Request URL via HTTP POST
router.post("/", function(req, res, next) {
    // Get event payload
    let payload = req.body;
    // Respond to this event with HTTP 200 status
    res.sendStatus(200);
}

Now that you've written code to handle an event, you can think about how to respond in a 'bot-like' way.

Responding to mentions using the Web API

For a bot, being mentioned is usually the triggering event for a conversation, just as a human will respond when they hear their name.

Your app code should use the type field inside the event payload to spot these app_mention events, and differentiate them from any other events it might receive.

In addition, you don't want to respond to every mention, only the ones that are actually intended to trigger the "tell a joke" flow.

To do that, use the text field from the event payload, which contains the text of the message that the mention was contained in. When text mentions the bot and includes the words "tell me a joke", the bot will respond; otherwise it'll just stay quiet.

Here's what the example code might look like with this kind of logic:

router.post("/", function(req, res, next) {
    let payload = req.body;
    res.sendStatus(200);

    if (payload.event.type === "app_mention") {
        if (payload.event.text.includes("tell me a joke")) {
            // Make call to chat.postMessage using bot's token
        }
    }
}

With the call to chat.postMessage, the first line of the joke is sent:

Knock, knock.

To send this, your app should use that API method with the token you stored earlier. Here's an example request:

POST https://slack.com/api/chat.postMessage
Content-type: application/json
Authorization: Bearer YOUR_BOTS_TOKEN
{
    "text": "Hello <@UA8RXUPSP>! Knock, knock.",
    "channel": "CBR2V3XEX"
}

You can read the API method reference for more info on building this request. You can, of course, use all the special formatting, attachments, and interactive components available for messages, but for now keep it simple.

So, your bot has uttered those first magical words, and you can assume that the user will reply with the standard "Who's there?" response. Let's find out how to keep the joke going.

Responding to other messages

As we said before, the flow we're describing contains an app_mention event followed by three message events. In order to identify the differences between those three messages, the app logic must become a bit more complex.

The first thing you need to do is use the type field inside the event payload to look for these message events.

Next, use the text of the message in the event payload to decide which kind of response your bot should make.

Again, let's assume the pattern of 'knock, knock' jokes - the first user response is always "Who's there?", and the second user response is always "____ who?". So, you can check for messages that include these words, and use the right bot response for each. If you see any messages that don't include either of these phrases, ignore them.

Added to the code from previous steps you'll have something like this:

router.post("/", function(req, res, next) {
    let payload = req.body;
    res.sendStatus(200);

    if (payload.event.type === "app_mention") {
        if (payload.event.text.includes("tell me a joke")) {
            // Make call to chat.postMessage using bot's token
        }
    }
    if (payload.event.type === "message") {
        let response_text;
        if (payload.event.text.includes("Who's there?")) {
            response_text = "A bot user";
        }
        if (payload.event.text.includes("Bot user who?")) {
            response_text = "No, I'm a bot user. I don't understand jokes.";
        }
        if (response_text !== undefined) {
            // Make call to chat.postMessage sending response_text using bot's token
        }
    }
}

Congratulations, your first bot is now alive and talking! You should now be able to go to the channel you installed the bot into and strike up this conversation with it. Remember to laugh politely when it tells you the punchline.

Your next steps should involve adding some more complexity to your bot to make it useful.


Making more complex bots

In the steps above, we made a lot of assumptions of simplicity. For example, we expected that users would respond with a very specific spelling, we assumed a test environment where there were no other conversations happening, and so on.

For a real bot in production, some of these assumptions would break the behavior of the bot. So let's cover some situations that you should address for your own bots - think of these as best practices rather than specific instructions to follow.

Tracking conversations

In our example bot, we've used a mention as the triggering point for a specific conversation, but you'll notice that your bot will still respond if you skip some of the steps - for example if you type Who's there?, your bot will respond to this message with A bot user, even if you didn't mention the bot or start at the beginning of the conversation.

A solution to this might involve tracking the beginning of a conversation, the participants involved, and the progress through the flow. For example, when the user first mentions the bot, a database entry is created that identifies that user and the open workflow with them.

As the user progresses through the flow, the database records this, and the user is unable to repeat earlier steps in the conversation (unless of course that is a desired behavior). Once the workflow is completed, the database entry is also marked as complete, and the bot waits for another mention before starting anew.

Threaded messages

Be aware that a user might choose to reply to your bot's messages in a thread rather than at the channel-level. Your bot will still receive message events for these threaded replies, but you will have to add some extra logic to ensure that your bot responds to the user in the relevant location.

Check out the Threading Messages docs for more information on how to spot the difference between messages and threaded messages.

Variations in phrasing

Because your bot will be interacting with humans, it's unlikely that you can expect consistent spelling and phrasing across messages from different people that might be trying to invoke the same thing. For example, our simple example bot used the phrase tell me a joke to trigger the start of the workflow, but at a very basic level a user might also try typing what's a good joke? or make me laugh.

Your bot can get more complex by broadening its understanding of natural language queries to capture a wider range of potential trigger phrases. Alternatively you can be more prescriptive about the exact phrasing to use, and provide user education to train correct usage.

Integrating with other services

The real magic of a bot comes when it is connected with external services, providing a seamless conversational interface for them from within Slack.

There's a huge range of possibilities for what your bot could do, so it might help to start with a great resource like the Botkit Community.


Limitations

Like other APIs and integrations, bot users are free. Unlike regular users, the actions they can perform are somewhat limited. For workspaces on the Free plan, each bot user counts as a separate integration.

API methods available to bots

Bot Users, and bot tokens, can be used with a slightly restricted set of Web API methods. These methods are shown below:

Method & Description Description
api.test
Checks API calling code.
Checks API calling code.
auth.test
Checks authentication & identity.
Checks authentication & identity.
bots.info
Gets information about a bot user.
Gets information about a bot user.
channels.info
Gets information about a channel.
Gets information about a channel.
channels.list
Lists all channels in a Slack team.
Lists all channels in a Slack team.
chat.meMessage
Share a me message into a channel.
Share a me message into a channel.
chat.postEphemeral
Sends an ephemeral message to a user in a channel.
Sends an ephemeral message to a user in a channel.
chat.postMessage
Sends a message to a channel.
Sends a message to a channel.
chat.update
Updates a message.
Updates a message.
conversations.close
Closes a direct message or multi-person direct message.
Closes a direct message or multi-person direct message.
conversations.history
Fetches a conversation's history of messages and events.
Fetches a conversation's history of messages and events.
conversations.info
Retrieve information about a conversation.
Retrieve information about a conversation.
conversations.list
Lists all channels in a Slack team.
Lists all channels in a Slack team.
conversations.members
Retrieve members of a conversation.
Retrieve members of a conversation.
conversations.open
Opens or resumes a direct message or multi-person direct message.
Opens or resumes a direct message or multi-person direct message.
dialog.open
Open a dialog with a user
Open a dialog with a user
dnd.info
Retrieves a user's current Do Not Disturb status.
Retrieves a user's current Do Not Disturb status.
dnd.teamInfo
Retrieves the Do Not Disturb status for users on a team.
Retrieves the Do Not Disturb status for users on a team.
files.comments.add
Add a comment to an existing file.
Add a comment to an existing file.
files.comments.delete
Deletes an existing comment on a file.
Deletes an existing comment on a file.
files.comments.edit
Edit an existing file comment.
Edit an existing file comment.
files.delete
Deletes a file.
Deletes a file.
files.info
Gets information about a team file.
Gets information about a team file.
files.upload
Uploads or creates a file.
Uploads or creates a file.
groups.info
Gets information about a private channel.
Gets information about a private channel.
groups.list
Lists private channels that the calling user has access to.
Lists private channels that the calling user has access to.
im.close
Close a direct message channel.
Close a direct message channel.
im.history
Fetches history of messages and events from direct message channel.
Fetches history of messages and events from direct message channel.
im.list
Lists direct message channels for the calling user.
Lists direct message channels for the calling user.
im.mark
Sets the read cursor in a direct message channel.
Sets the read cursor in a direct message channel.
im.open
Opens a direct message channel.
Opens a direct message channel.
im.replies
Retrieve a thread of messages posted to a direct message conversation
Retrieve a thread of messages posted to a direct message conversation
mpim.close
Closes a multiparty direct message channel.
Closes a multiparty direct message channel.
mpim.history
Fetches history of messages and events from a multiparty direct message.
Fetches history of messages and events from a multiparty direct message.
mpim.list
Lists multiparty direct message channels for the calling user.
Lists multiparty direct message channels for the calling user.
mpim.mark
Sets the read cursor in a multiparty direct message channel.
Sets the read cursor in a multiparty direct message channel.
mpim.open
This method opens a multiparty direct message.
This method opens a multiparty direct message.
oauth.access
Exchanges a temporary OAuth verifier code for an access token.
Exchanges a temporary OAuth verifier code for an access token.
oauth.token
Exchanges a temporary OAuth verifier code for a workspace token.
Exchanges a temporary OAuth verifier code for a workspace token.
pins.add
Pins an item to a channel.
Pins an item to a channel.
pins.remove
Un-pins an item from a channel.
Un-pins an item from a channel.
reactions.add
Adds a reaction to an item.
Adds a reaction to an item.
reactions.get
Gets reactions for an item.
Gets reactions for an item.
reactions.list
Lists reactions made by a user.
Lists reactions made by a user.
reactions.remove
Removes a reaction from an item.
Removes a reaction from an item.
rtm.connect
Starts a Real Time Messaging session.
Starts a Real Time Messaging session.
rtm.start
Starts a Real Time Messaging session.
Starts a Real Time Messaging session.
stars.add
Adds a star to an item.
Adds a star to an item.
stars.remove
Removes a star from an item.
Removes a star from an item.
team.info
Gets information about the current team.
Gets information about the current team.
users.conversations
List conversations the calling user may access.
List conversations the calling user may access.
users.getPresence
Gets user presence information.
Gets user presence information.
users.info
Gets information about a user.
Gets information about a user.
users.list
Lists all users in a Slack team.
Lists all users in a Slack team.
users.lookupByEmail
Find a user with an email address.
Find a user with an email address.
users.setActive
Marked a user as active. Deprecated and non-functional.
Marked a user as active. Deprecated and non-functional.
users.setPresence
Manually sets user presence.
Manually sets user presence.