How To Write A Slack Bot — End to End
This post is now out of date, but is archived here for people who would like to see what it originally said, or are using a deprecated version of the Slack API.
Rather than follow this, please follow the updated version of this article, "How to Write a Slack Bot - End to End", current as of 6/01/20.
Cyclone Bass Bot image by David J under a Creative Commons License.
If you use Slack at your company, like automation, but haven’t been able to test the waters of implementation, this post is for you. There will be no intermediaries required if you follow this guide (well, besides Slack). The idea
is, by following this guide, the code examples, and Slack’s documentation, you’ll be able to get a bot up and running in short order using knowledge you either already have or can get from the Internet. If that’s not enough, I’ve written a Part II that goes into more detail and a Part III with clean, simplified standup bot code available on GitHub.
Every article-length programming guide has to make assumptions to avoid book-sized bloat. This article assumes you know or can learn Python reasonably well, though to give some context, outside of “hello world” style exercises, this is my most serious foray into Python.
If you don’t know Python, or only know a little JavaScript or a language along those lines, never fear. You can still build a bot, after using this guide. The idea is to get you to a place, knowledge-wise, where Stack Overflow and the like can carry you the rest of the way, once you have the core details down.
What kinds of bots are we talking about? A bot that, say, asks a series of individual people in direct message chats for stand-up details, and then posts them to a room; a bot that tips people a very small amount of BitCoin, using Slack and a API; a bot that listens for keywords (say, “help Jenkins”) and then posts links to knowledge base articles on the topic. These are all real-world examples, as I’ve been tweaking my bot for these tasks. We are NOT talking about pre-built bots such as the readily available JIRA or GitHub bots, since those are plug and play — no coding required.
So without further ado, here’s how to create your own bot using Python.
1. Use Slack’s Python library.
https://github.com/slackapi/python-slackclient
Why this one, and not others? It’s produced by the people who made the product so it’s the one I used, using my “as few intermediaries as possible” rule. Others might be as good, or better. However, from what I can tell, this one includes all the necessary functionality; I haven’t found anything I wanted to but couldn’t do with it.
2. Figure out how your bot should respond.
Your bot has a couple of possible modes. It can:
a) respond when you start it, as in the example of a pre-meeting information-gathering bot; it initiates conversation, gathers the necessary material, and then stops. Call this sequential.
b) be on at all times, as in the example of Q&A-type bot (“bot lunch”, “Hello! Here are some good options in our neighborhood…”); it sits around listening to events, and springs into action whenever you say the magic key word (“hello bot” or “tipbot send 1 bit to @ben”). Call this event-driven.
Note that sequential is easy to implement: whenever I want to run it, I execute “python script.py” at the command line. Presto, it runs. Event-driven is only going to be running when the machine of the owner is running it in the background, or (more likely) it’s uploaded to a server where it can run 24–7 and all employees can access the bot’s functionality at any time.
3. How Slack’s API ‘thinks’
Bookmark the API methods page, because it is your most important reference.
You might think that everything in Slack is a room, or a channel, and that channels only differ in their permission levels (public, private). That is a reasonable assumption; after all, I made it. Alas, it’s wrong.
In Slack, permissions make a huge difference. All rooms are not created equal; permissions are so important that rooms with different permissions belong to completely different categories.
The one we intuitively recognize is the channel. Groups are like private channels, as I see it. IM’s are in a different category: when you and the bot have a conversation, made up exclusively of direct messages, that is an IM. These distinctions are important because they dictate which of the methods at the link above you’ll be using, and can assist you as you reason through your bot’s interactions.
4. Less Talk, More Action!
What are the most important things you need to know? They are:
a) For every method, there’s a tester — use it!
b) Slack’s Python library follows the syntax method extremely closely, so much so that you can look at the method name and guess almost every time exactly what to call.
c) Here’s the method to post to rooms:
https://api.slack.com/methods/chat.postMessage
Here’s a Python example of it in action:
sc.api_call(“chat.postMessage”, as_user=”true”, channel=”D0X8ZEXAX”, text=”whatever you want to say”)
d) Here’s the method to post to individuals:
https://api.slack.com/methods/im.open
You can run your bot script using this method against a user, then get the channel you use chat.postMessage with to message the individual.
Here’s an example of this in action:
print sc.api_call(“im.open”, user=”U07QKAOLB”)
e) You can use this endpoint to get the ID’s of any user in the company. One use for this would be to find out a user’s ID, then to feed it to the chat.postMessage method listed above.
https://api.slack.com/methods/users.list
You can use the tester in the browser to retrieve all of this information. Go ahead and rely on it; while I know that I could write http request scripts to get this information, I often use the tester because it’s so convenient.
f) For a real-time event-driven bot that’s always listening and responding to certain things, see the example given on the Python-slackclient GitHub page (with a fake token, naturally).
import time
from slackclient import SlackClient
token = "xoxo-89234987234987234798098"
sc = SlackClient(token)
if sc.rtm_connect():
while True:
print sc.rtm_read()
time.sleep(1)
else:
print "Connection Failed, invalid token?"
import time, json, yaml, re, os
from slackclient import SlackClient
while True:
new_evts = sc.rtm_read()
for evt in new_evts:
print(evt)
if "type" in evt:
if evt["type"] == "message" and "text" in evt:
message=evt["text"]
time.sleep(3)
Hopefully, this will get you started. Due to space constraints, there’s a lot I left out, but these are the basics of a generic Slack bot. Feel free to comment below for more help, and I’ll be happy to answer.
There’s plenty of untapped potential in the area of office productivity enhancements, at the intersection of third-party tools, domain knowledge, configuration savvy, and simple scripting.
Slack bots are a perfect example of this, and bot knowledge—how to create them, and use them to make your work more productive—is going to be big for a long time to come.