How to build a Slack Bot with Python using Slack Events API & Django under 20 minute— Code Included

Prabakaran Kumaresshan
freehunch
Published in
10 min readJul 22, 2017

Slack is a great platform for team collaboration not just that it also has one of the best API interfaces to build Chatbots. Chatbots come in all size from reminding you to buy milk to help you send or receive money.

In this post, I will walk you through building a minimal Slack Bot with Python backend. The idea is to set up a Slack Bot that will greet you back when greeted, once we have it up and running then we can extend the Bots ability just by coding additional logic.

Minute 1: Slack

Before we start coding the bot let us understand the Slack bots life cycle:

  1. If you are new to Slack, it’s a messaging platform focused on team collaboration. Slack lets you create custom applications, including bots (sort of Messaging Platform as a Service). You will run the application back end to process business logic in your own server.
  2. To startwith you need to be part of Slack team and have admin privilege to create a new Slack App. If you are not part of a Slack team you may create one.
  3. We will create a Slack App for the Slack team then we will add a Bot User to the app.
  4. We will create a Django based REST backend web application to process the Bot User requests.
  5. Since we will be running the backend in our local system, we will use ngrok to tunnel our local network and get a public url.
  6. Once the backend is ready we can submit the endpoint url to Slack for url verification by challenge. When you submit an endpoint for the first time Slack will send a challenge POST request with a secret token. To successfully complete the challenge you need to return the request with the challenge secret (you just have to echo the received message). This is a one time excercise for a given api endpoint.
  7. Once verified we can subscribe to events for which we want Slack to send a message to our backend. This is the best part you dont have to pool Slack to get new events, Slack will do the heavy lifting, which makes this an excellent use case for AWS Lambda. You can find the long list of events here.
  8. After setting up Slack App and have the backend ready to process events, we can write the bot logic to perform a specific task in response to an event. In this case when a user greets, our bot will respond with a greet message.

Lets dive into Bot Building…

Minute 2: Create a Slack App

Start by creating a Slack app here, click Create App. Then proceed with app creation, give it a name and select the Slack team.

Then you will be taken to App configuration where you need do following to get our Bot up and running.

  1. Create a Bot User
  2. Install Slack App to your Team
  3. Verify Back End
  4. Subscribe to Events

On the left pane click on Bot User then choose an user name for the Bot and set “Always Show My Bot as Online” slider to on. Since we are going to use Events API only, the bot will not appeare online otherwise. Click on Add Bot User to create our hello bot.

Minute 3: Install Slack App to Team

Now on the left pane click Install App and install the app to your Slack team.

Once installed you will get Bot User OAuth Access Token, note down this token we will need it later while configuring Django app. This token is the passphrase for our Bot to interact with the Slack Team. We will refer to this token as SLACK_BOT_USER_TOKEN in rest of the tutorial.

Minute 4: Slack Client Credentials

Also note down the App Credentials from Basic Information on the left pane. These credentials let us talk to Slack API, so every time we send a message to Slack we should send our Client ID(CLIENT_ID) & Client Secret(CLIENT_SECRET) to identify ourselves to Slack. Similarly we can verify if an incomming message is send by Slack checking if the Verification Token (VERIFICATION_TOKEN) in the message is same as the one in App Credentials.

Now we should have four key values with us

  1. Client ID — SLACK_CLIENT_ID
  2. Client Secret — SLACK_CLIENT_SECRET
  3. Verification Token — SLACK_VERIFICATION_TOKEN
  4. Bot User Token — SLACK_BOT_USER_TOKEN

We have one last step left in Slack App configuration, which is to submit our Bot’s REST API end point to Slack and get it verified.

Before we Verify our Bot and subscribe for the events, we need to have the Django app running.

Minute 5: Environment Setup

We will be using Python 3.5 and following packages

  1. Django
  2. Django REST Framework
  3. Slack Client for Python
  4. Slack Events API

We will use conda for virtual environment and pip for package management. Let us create new virtual environment “slack_bot” for our project with python version 3.5.x and activate the virtual environment.

conda create -n slack_bot python==3.5# windows
activate slack_bot
# mac os, linux
source activate slack_bot

Now lets install required packages

pip install django
pip install djangorestframework
pip install slackclient
pip install slackeventsapi

Minute 6: Create Django Application

Create a django project and an app in the working directory.

django-admin startproject slack
cd slack
django-admin startapp events

Now your project folder structure should look like this. From now on all the file path I mention assumes slack, the project folder, as root.

└── slack
├── events
│ ├── admin.py
│ ├── apps.py
│ ├── __init__.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── manage.py
└── slack
├── __init__.py
├── __pycache__
│ ├── __init__.cpython-35.pyc
│ ├── settings.cpython-35.pyc
│ ├── urls.cpython-35.pyc
│ └── wsgi.cpython-35.pyc
├── settings.py
├── urls.py
└── wsgi.py

Minute 7: Configure Django Settings

REST Framework makes creating API end points a breeze with build-in API Views and browseable API. Lets add REST Framework as dependency in Django settings. Also we need to add our own application events as dependency. Add the two lines mentioned below in the file slack/settings.py

# slack/settings.pyINSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework', # <== add this line
'events', # <== add this line
]

Then add following configurations in slack_bot/settings.py with your authentication keys from Slack.

# slack/settings.py# SLACK API Configurations
# ----------------------------------------------
# use your keys
SLACK_CLIENT_ID = '20xxxxxxxxxx.20xxxxxxxxxx'
SLACK_CLIENT_SECRET = 'd29fe85a95c9xxxxxxxxxxxxxxxxxxxxx'
SLACK_VERIFICATION_TOKEN = 'xpxxxxxxxxxxxxxxxxxxxxxxxxx'
SLACK_BOT_USER_TOKEN = 'xoxb-xxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxx'

Please do not check in your code into any public repository like Github with these values saved. Ideally these values should be exported as environment variables and read by startup scripts.

Now start the Django development server

python manage.py runserver

Once the server is started it will print something similar to this

Performing system checks…
System check identified no issues (0 silenced).
You have 13 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run ‘python manage.py migrate’ to apply them.
July 03, 2017–17:30:32
Django version 1.11.3, using settings ‘slack.settings’
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Ignore the migration warnings and open the URL in your browser.

Minute 8: Create an API endpoint

Now that we have our app server up and running we need to create an endpoint for Slack to send event messages. We will create an API view with Django Rest Framework (DRF) as follows

# events/views.pyfrom rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.conf import settings

SLACK_VERIFICATION_TOKEN = getattr(settings, 'SLACK_VERIFICATION_TOKEN', None)

class Events(APIView):
def post(self, request, *args, **kwargs):
slack_message = request.data if slack_message.get('token') != SLACK_VERIFICATION_TOKEN:
return Response(status=status.HTTP_403_FORBIDDEN)
return Response(status=status.HTTP_200_OK)

In the code above we are importing the required python packages, retreiveing the token saved in configuration then defining an API view to handle POST request.

In the POST function we are checking if the token in message matches our Bot User’s verification token, this is to validate if the incomming request was actually from Slack. If there is match we are sending “OK” message else telling that the requester is “Forbidden” from accessing our server.

Minute 9: Configure Django Routes

If you are new to web applications, routing is the way to tell web server which function to invoke when an URL is hit with a request. When the URL is hit with a request message the corresponding function will be invoked, passing the requester message as parameter to the function.

Add following lines in slack/urls.py to tie Events API class to http://localhost:8000/events/

# slack/urls.pyfrom django.conf.urls import url
from django.contrib import admin
from events.views import Events #

urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^events/', Events.as_view()), #
]

Open the server url in your browser, you will find bowserable API interface.

Note: Usually we will create a separate routing file for each app and register it with the project route. To keep the code simple I have defined the events app url in the project route file.

Minute 10: Slack URL Verification Challenge

In order to submit our API endpoint to Slack we need to code a logic to let Slack verify our endpoint and associate it with the Slack Bot User. In the Events API class add following code.

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.conf import settings

SLACK_VERIFICATION_TOKEN = getattr(settings, 'SLACK_VERIFICATION_TOKEN', None)


class Events(APIView):
def post(self, request, *args, **kwargs):

slack_message = request.data

if slack_message.get('token') != SLACK_VERIFICATION_TOKEN:
return Response(status=status.HTTP_403_FORBIDDEN)

# verification challenge
if slack_message.get('type') == 'url_verification': #
return Response(data=slack_message, #
status=status.HTTP_200_OK) #

return Response(status=status.HTTP_200_OK)

What we are doing here is checking if the request is an url verification, if yes then relaying the same message back.

Minute 11: The Greet Bot

Lets code the greet bot, we will keep the logic simple. We are not going to use Natural Language Processing (NLP) for now, saving it for later. We will look for greet word “Hi” in user’s message if the word is found the bot will respond with a text like

In the Events API add following lines marked by #

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.conf import settings
from slackclient import SlackClient #1


SLACK_VERIFICATION_TOKEN = getattr(settings, 'SLACK_VERIFICATION_TOKEN', None)
SLACK_BOT_USER_TOKEN = getattr(settings, #2
'SLACK_BOT_USER_TOKEN', None) #
Client = SlackClient(SLACK_BOT_USER_TOKEN) #3


class Events(APIView):
def post(self, request, *args, **kwargs):

slack_message = request.data

if slack_message.get('token') != SLACK_VERIFICATION_TOKEN:
return Response(status=status.HTTP_403_FORBIDDEN)

# verification challenge
if slack_message.get('type') == 'url_verification':
return Response(data=slack_message,
status=status.HTTP_200_OK)
# greet bot
if 'event' in slack_message: #4
event_message = slack_message.get('event') #

# ignore bot's own message
if event_message.get('subtype') == 'bot_message': #5
return Response(status=status.HTTP_200_OK) #

# process user's message
user = event_message.get('user') #6
text = event_message.get('text') #
channel = event_message.get('channel') #
bot_text = 'Hi <@{}> :wave:'.format(user) #
if 'hi' in text.lower(): #7
Client.api_call(method='chat.postMessage', #8
channel=channel, #
text=bot_text) #
return Response(status=status.HTTP_200_OK) #9

return Response(status=status.HTTP_200_OK)

What we have done is

  1. Imported Slack Client package.
  2. Retrived Slack Bot User Token from settings.
  3. Created a Client instance to post bot response to Slack.
  4. If event data is available in the received message, then process the message.
  5. The message posted by bot to a channel will be received by the bot again as part of receipient. So the bot message must be ignored by bot.
  6. If the message is from a user then process the event. Extract user id, channel id and the user message to bot. Then build the bot’s greet message with user name.
  7. If the user message contains the greet word “hi”, then proceed with posting the greet message.
  8. We are invoking Slack Client API to post the Bot response message to the channel via chat.postMessage.
  9. Once the message is posted return OK to the Slack event.

Here a depiction of the bot logic.

Minute 12: Tunneling with ngrok

Now we need make our bot available in a public domain for Slack to make service calls. One way to do it in your local system is to user a tunneling service like ngrok, go ahead and install ngrok for you system.

Once you have setup ngrok

  1. Start Django server with command
python manage.py runserver 0.0.0.0:8000

2. Use ngrok to bind your Django port to a public domain as follows

ngrok http 8000

ngrok will create a public URL and forward the requests to your server, you will see something like below on successful binding.

To access your Bot API go to http://<your-unique-id>.ngrok.io/events/

Minute 13: Submitting URL to Slack

Goto to Slack Apps dashboard select your app and subscribe to events by giving the ngrok URL.

Your URL should pass the verification challenge.

Then scroll down to subscribe for channel message and direct message.

Minute 14: Thats All Folks

Your bot is up and running now, go ahead and say to it in Slack Chat.

--

--