You must enable javascript in order to use Slack. You can do this in your browser settings.
New Slack apps can act independently of a user token. Build a bot user powered by only the specific permissions it needs.

Enabling interactions with bots

This article describes an outdated approach to Slack apps. New Slack apps act independently of a user token. Build a bot user powered by only the specific permissions it needs. Check out new Slack apps now.

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

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:

Methods for the modern bot

Method & DescriptionDescription
apps.auth.external.delete
Delete external auth tokens only on the Slack side
Delete external auth tokens only on the Slack side
apps.auth.external.get
Get the access token for the provided token ID
Get the access token for the provided token ID
apps.datastore.delete
Delete an item from a datastore
Delete an item from a datastore
apps.datastore.get
Get an item from a datastore
Get an item from a datastore
apps.datastore.put
Creates a new item, or replaces an old item with a new item.
Creates a new item, or replaces an old item with a new item.
apps.datastore.query
Query a datastore for items
Query a datastore for items
apps.datastore.update
Edits an existing item's attributes, or adds a new item if it does not already exist.
Edits an existing item's attributes, or adds a new item if it does not already exist.
apps.uninstall
Uninstalls your app from a workspace.
Uninstalls your app from a workspace.
auth.revoke
Revokes a token.
Revokes a token.
auth.teams.list
Obtain a full list of workspaces your org-wide app has been approved for.
Obtain a full list of workspaces your org-wide app has been approved for.
auth.test
Checks authentication & identity.
Checks authentication & identity.
bookmarks.add
Add bookmark to a channel.
Add bookmark to a channel.
bookmarks.edit
Edit bookmark.
Edit bookmark.
bookmarks.list
List bookmark for the channel.
List bookmark for the channel.
bookmarks.remove
Remove bookmark from the channel.
Remove bookmark from the channel.
bots.info
Gets information about a bot user.
Gets information about a bot user.
calls.add
Registers a new Call.
Registers a new Call.
calls.end
Ends a Call.
Ends a Call.
calls.info
Returns information about a Call.
Returns information about a Call.
calls.participants.add
Registers new participants added to a Call.
Registers new participants added to a Call.
calls.participants.remove
Registers participants removed from a Call.
Registers participants removed from a Call.
calls.update
Updates information about a Call.
Updates information about a Call.
channels.create
Creates a channel.
Creates a channel.
channels.info
Gets information about a channel.
Gets information about a channel.
channels.invite
Invites a user to a channel.
Invites a user to a channel.
channels.mark
Sets the read cursor in a channel.
Sets the read cursor in a channel.
chat.delete
Deletes a message.
Deletes a message.
chat.deleteScheduledMessage
Deletes a pending scheduled message from the queue.
Deletes a pending scheduled message from the queue.
chat.getPermalink
Retrieve a permalink URL for a specific extant message
Retrieve a permalink URL for a specific extant message
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.scheduleMessage
Schedules a message to be sent to a channel.
Schedules a message to be sent to a channel.
chat.scheduledMessages.list
Returns a list of scheduled messages.
Returns a list of scheduled messages.
chat.unfurl
Provide custom unfurl behavior for user-posted URLs
Provide custom unfurl behavior for user-posted URLs
chat.update
Updates a message.
Updates a message.
conversations.acceptSharedInvite
Accepts an invitation to a Slack Connect channel.
Accepts an invitation to a Slack Connect channel.
conversations.approveSharedInvite
Approves an invitation to a Slack Connect channel
Approves an invitation to a Slack Connect channel
conversations.archive
Archives a conversation.
Archives a conversation.
conversations.close
Closes a direct message or multi-person direct message.
Closes a direct message or multi-person direct message.
conversations.create
Initiates a public or private channel-based conversation
Initiates a public or private channel-based conversation
conversations.declineSharedInvite
Declines a Slack Connect channel invite.
Declines a Slack Connect channel invite.
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.invite
Invites users to a channel.
Invites users to a channel.
conversations.inviteShared
Sends an invitation to a Slack Connect channel
Sends an invitation to a Slack Connect channel
conversations.join
Joins an existing conversation.
Joins an existing conversation.
conversations.kick
Removes a user from a conversation.
Removes a user from a conversation.
conversations.leave
Leaves a conversation.
Leaves a conversation.
conversations.list
Lists all channels in a Slack team.
Lists all channels in a Slack team.
conversations.listConnectInvites
Lists shared channel invites that have been generated or received but have not been approved by all parties
Lists shared channel invites that have been generated or received but have not been approved by all parties
conversations.mark
Sets the read cursor in a channel.
Sets the read cursor in a channel.
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.
conversations.rename
Renames a conversation.
Renames a conversation.
conversations.replies
Retrieve a thread of messages posted to a conversation
Retrieve a thread of messages posted to a conversation
conversations.setPurpose
Sets the purpose for a conversation.
Sets the purpose for a conversation.
conversations.setTopic
Sets the topic for a conversation.
Sets the topic for a conversation.
conversations.unarchive
Reverses conversation archival.
Reverses conversation archival.
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 up to 50 users on a team.
Retrieves the Do Not Disturb status for up to 50 users on a team.
emoji.list
Lists custom emoji for a team.
Lists custom emoji for a team.
files.comments.delete
Deletes an existing comment on a file.
Deletes an existing comment on a file.
files.completeUploadExternal
Finishes an upload started with files.getUploadURLExternal
Finishes an upload started with files.getUploadURLExternal
files.delete
Deletes a file.
Deletes a file.
files.getUploadURLExternal
Gets a URL for an edge external file upload
Gets a URL for an edge external file upload
files.info
Gets information about a file.
Gets information about a file.
files.list
List for a team, in a channel, or from a user with applied filters.
List for a team, in a channel, or from a user with applied filters.
files.remote.add
Adds a file from a remote service
Adds a file from a remote service
files.remote.info
Retrieve information about a remote file added to Slack
Retrieve information about a remote file added to Slack
files.remote.list
Retrieve information about a remote file added to Slack
Retrieve information about a remote file added to Slack
files.remote.remove
Remove a remote file.
Remove a remote file.
files.remote.share
Share a remote file into a channel.
Share a remote file into a channel.
files.remote.update
Updates an existing remote file.
Updates an existing remote file.
files.upload
Uploads or creates a file.
Uploads or creates a file.
groups.create
Creates a private channel.
Creates a private channel.
groups.info
Gets information about a private channel.
Gets information about a private channel.
groups.invite
Invites a user to a private channel.
Invites a user to a private channel.
groups.mark
Sets the read cursor in a private channel.
Sets the read cursor in a private channel.
groups.open
Opens a private channel.
Opens a private 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.
migration.exchange
For Enterprise Grid workspaces, map local user IDs to global user IDs
For Enterprise Grid workspaces, map local user IDs to global user IDs
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.
pins.add
Pins an item to a channel.
Pins an item to a channel.
pins.list
Lists items pinned to a channel.
Lists items pinned 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.
stars.add
Save an item for later. Formerly known as adding a star.
Save an item for later. Formerly known as adding a star.
team.billing.info
Reads a workspace's billing plan information.
Reads a workspace's billing plan information.
team.info
Gets information about the current team.
Gets information about the current team.
team.preferences.list
Retrieve a list of a workspace's team preferences.
Retrieve a list of a workspace's team preferences.
team.profile.get
Retrieve a team's profile.
Retrieve a team's profile.
usergroups.create
Create a User Group
Create a User Group
usergroups.disable
Disable an existing User Group
Disable an existing User Group
usergroups.enable
Enable a User Group
Enable a User Group
usergroups.list
List all User Groups for a team
List all User Groups for a team
usergroups.update
Update an existing User Group
Update an existing User Group
usergroups.users.list
List all users in a User Group
List all users in a User Group
usergroups.users.update
Update the list of users for a User Group
Update the list of users for a User Group
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.profile.get
Retrieve a user's profile information, including their custom status.
Retrieve a user's profile information, including their custom status.
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.
views.open
Open a view for a user.
Open a view for a user.
views.publish
Publish a static view for a User.
Publish a static view for a User.
views.push
Push a view onto the stack of a root view.
Push a view onto the stack of a root view.
views.update
Update an existing view.
Update an existing view.
workflows.stepCompleted
Indicate that an app's step in a workflow completed execution.
Indicate that an app's step in a workflow completed execution.
workflows.stepFailed
Indicate that an app's step in a workflow failed to execute.
Indicate that an app's step in a workflow failed to execute.
workflows.updateStep
Update the configuration for a workflow step.
Update the configuration for a workflow step.

Methods for classic bots

Method & DescriptionDescription
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.
calls.add
Registers a new Call.
Registers a new Call.
calls.end
Ends a Call.
Ends a Call.
calls.info
Returns information about a Call.
Returns information about a Call.
calls.participants.add
Registers new participants added to a Call.
Registers new participants added to a Call.
calls.participants.remove
Registers participants removed from a Call.
Registers participants removed from a Call.
calls.update
Updates information about a Call.
Updates information about a Call.