Building a World Cup Bot with Python, Twilio SMS and Slack
Time to read: 11 minutes
The World Cup. For us Brazilians, it’s like the Super Bowl, NBA Finals, World Series, and Stanley Cup, combined, multiplied by 100.
For those of us diehard ‘futebol’ fans following the games in Russia from the Western hemisphere, it’s been quite the challenge keeping up since most of the games are on while we’re at work.
I knew I wasn’t the only one in the office trying to keep up with the games. To solve this problem I created a bot that combines the Slack API with the Twilio SMS API to provide fans with real-time updates of every exciting moment in every world cup game – fouls, penalties, goals, and all.
This post will walk through how I built it. Feel free to follow these instructions to build your own World Cup bot or a bot for your sport of preference. You can check out the final code here.
Alright, let’s roll!
World Cup 2018 greatest moments
Tools We Need
Our bot, which we’ll name WorldCupBot, requires a few libraries and APIs. To build our bot we need:
- pip and virtualenv to handle the Python application dependencies
- Python 3.6
- Flask web microframework – if you’re unfamiliar with Flask, many learning resources are available.
Here’s a handy step-by-step guide to setting up Python, pip, virtualenv and Flask.
The Slack dependencies are:
- Free Slack account with a team on which you have API access or sign up for the Slack Developer Hangout team
- Official Python slackclient code library built by the Slack team
- Slack API docs
- Slack API testing token
Our Twilio requirements include:
Set up our environment
Before we get started, let’s set up our environment. This project was written in Python 3.6. Create a new directory to work with and activate a Python 3 virtualenv:
Next, we will install the packages we will need on our project directory:
Now, we will create a .env
file at the root directory to store the credentials we will need to interact with Twilio and Slack APIs. It will look like this:
We will add the credentials to this file later on. Since you most likely don’t want to commit your environment variables to a repository, make sure to add the .env file to your .gitignore to avoid accidentally pushing it.
For this project, we will use the python-dotenv library to load the .env file – this will make our lives easier. If you prefer, you can source the environment variables from your terminal.
Now let’s get the access token and bot ID for Slack and our Twilio credentials.
Slack Real Time Messaging API
If you don’t already have a Slack organization to work with, first create that. Since we’ll be using the Slack API, click the “Create a Slack App” button circled below:
This will return this web page, where you can enter your app’s name. Make sure you add a meaningful name – mine is ‘pythonworldcupbot’. Once you fill out the information, click “Create App”.
Several options will appear that you can add to your application, including “Bots” which is circled below.
Just as you’ve done before, fill out the needed fields and select “Add Bot User”.
You’ll need the default username later on, so take note of it!
Next, on the left sidebar click the option ‘OAuth & Permissions’, then click ‘Install App to your Workspace’. Copy the Bot User OAuth Access Token and save it as SLACK_BOT_TOKEN
in your .env
file.
Getting your Slack Bot ID
Let’s write a quick Python script to get callbot’s ID because it varies based on the Slack team. We need the callbot ID because it will allow our application code to determine if messages parsed from the Slack Real Time Messaging API are directed at our bot.
This script will also help test that our SLACK_BOT_TOKEN
environment variable is set properly. Create a new file named get_slackbot_id.py
with the following code:
The BOT_NAME
variable should be assigned to the name you gave to your bot while setting up the Slack app.
The above code imports SlackClient and instantiates it with our SLACK_BOT_TOKEN
. When the script is executed by the python
command we hit the API for a list of Slack users and get the ID for the one that matches the name pythonworldcupbot
(or the bot of your preference).
We only need to run this script once to obtain our bot’s ID.
When we run the script, we’ll get a single line of output with our Bot’s ID.
Copy the ID and add it to your .env
file as the SLACK_BOT_ID variable value.
Great! Now we just need to get our Twilio account credentials and we will be screaming “GOOOOOOOOOOOOOOOOOOOAAAAAAAAALLLLLL” in no time.
Twilio Messaging Service
We need access to the Twilio API to make phone calls from our application. Sign up for a Twilio account or log into your existing account if you already have one.
One of the most interesting features of our bot is the ability to send World Cup updates in real time. A regular Twilio number can only send 1 message per second. If we get up to 60 subscribers this is going to take a whole minute to send the messages and it gets worse from there.
We can prepare for this with a messaging service. Messaging services can pool numbers and scale sending out over the whole pool. As our subscriber base grows we can add numbers to keep up with demand.
Jump into the Twilio console, select ‘Programmable SMS’ and create a new Messaging Service, enter a friendly name of your preference and select “Chat Bot/Interactive 2 way” from the use case drop down.
Instead of using a “From” number to send messages, we will use the messaging service SID. Grab hold of the SERVICE SID and add it to the
TWILIO_MESSAGING_SERVICE_SID
credential on your .env
file.
Then go to the numbers section for this service and add a number to the service. You can use one of our active numbers or get a new one.
Finally, go to the Console Dashboard screen and look for your Twilio Account SID and Auth Token:
Setting up your Flask App
We have all the appropriate environment variables set for our Python code to appropriately use the Twilio and Slack APIs.
Now let’s get this ball rolling by writing a module to send SMS your subscribers.
Create a new file named server.py
on your project directory and import these dependencies:
Next, add the code to instantiate and run the flask app, as well as the environment variables that we will retrieve using the dotenv library:
Save your work and get back to your terminal. On the same directory where the server.py lives, create a new file named subscribers.csv
. We will use this file to store the phone numbers of your subscribers as comma-separated values. This format is the most common import and export format for spreadsheets and databases. We won’t be using any persistent data storages in this tutorial, but we need to save the numbers somewhere.
Next, let’s add the path to our subscribers.csv
to our server.py
module. We will also write some helper functions to add new phone numbers and retrieve a list of subscribers:
Now we can retrieve a list of phone numbers. Next, we will write some helper functions to loop over these numbers and send each one of them an SMS. To achieve our goal
of sending multiple messages at once, we will use Twilio’s Messaging Service.
What if we want to confirm that a phone number really exists before sending a text?
While we don’t have VAR to assist us with this one, fortunately we have an easy way to check if a number is valid with Twilio Lookup API.
Twilio Lookup is a simple REST API for obtaining information about a phone number. Lookup can determine if a number exists, its type (landline, mobile, VoIP), and its carrier (Verizon, Sprint, etc) association. Lookup can also check if a number is able to receive text messages as well as format numbers into a standard format.
Still on our server.py
, let’s write another helper function that calls the Twilio lookup api to check if a number is valid:
We are almost done with our server module. We still need to add two routes on this app: /subscribe
to add new users to our subscribers list, and /updates
to send SMS to our subscribers list when an interesting event happens during a game.
Let’s start with /subscribe
:
This endpoint can be called via an HTTP POST request. It calls the helper functions we wrote previously to: 1) verify if the number is valid and 2) if it is valid, send an SMS to the number confirming the subscription.
It returns a json with a ‘message’ attribute and the corresponding HTTP Status.
Now, let’s add our final endpoint, /updates
:
Here, once again, we have an endpoint that is reached via HTTP POST request.
Our helper functions will retrieve the list of subscribers, and iterate over the list to send every number a text. If we run into an error, it will return a JSON with the corresponding error message.
Let’s fire up our Flask app by running:
The app will start and expose the subscribe
and updates
routes on http://localhost:5000.
Using the Slack Web API
The central part of this project is the Slack bot. It will post World Cup updates to the channel of your choice. You’ll also be able to subscribe to SMS updates via the Slack bot.
Let’s write some code to achieve this.
First, let’s let our flask app running and open up a new terminal. On your project directory, activate the virtualenv and create a new file named slack_handler.py
.
Open the module on the editor of your choice, and add the following imports:
Now that we have imported our dependencies we can use python-dotenv
to grab those environment variables values and instantiate the Slack and Twilio clients.
Our code instantiates the SlackClient with our SLACK_BOT_TOKEN
. The TwilioRestClient
uses the TWILIO_ACCOUNT_SID
and TWILIO_AUTH_TOKEN
to be instantiated.
Next, we will kick off the bot with the following code:
SlackClient
connects to the Slack Real Time Messaging API WebSocket connection. With the ‘While True’ statement we create a continuous loop that reads all the data coming the API. If any of those messages are directed at our bot, a function named handle_command
will determine what to do with the command.
Above the Python code we just wrote, add four new functions to parse Slack output, handle commands and post messages:
The parse_slack_output
function takes messages from Slack and determines if they are directed at our WorldCupBot. If a message starts with a direct message to our bot ID, then we know our bot needs to handle a command. handle_command
function calls the add_subscriber
if the command is valid, and calls post_to_slack
with a success or failure message.
Add_subscriber
makes a POST request to our Flask app /subscribe
endpoint. If the number is valid, it adds to the subscribers.csv file and returns a success message. It returns a failure message otherwise.
Now let’s fire up the slack handler by running the python slack_handler.py
command. You should see a success message:
Testing out our Slack Bot
With the server.py and slack_handler.py running, open up the slack channel you configured to receive the World Cup updates (or create a new one). Add the pythonworldcupbot
to the channel by clicking on Add an app
or @mentioning the bot.
Try sending a random message to the bot – if everything is working properly, the bot will reply prompting you to use the command word subscribe
followed by your phone number.
If you @mention the bot followed by the word subscribe
and a valid number, you will receive a success message on slack and on your cell phone:
Creating our World Cup Events Notifier
Let’s start by writing a module to interact with the FIFA World Cup API, which is a URL that returns some JSON.
We are finally approaching the final whistle. The final step on our World Cup bot project is to write a module that will interact with the FIFA API and get updates on live matches. It will also call the post_to_slack
function from our slack_handler
module and generate a post request to our /updates
endpoint.
Create a new file named notifier.py
and add the following imports:
Next, we will declare constants that represent the game events that are meaningful to us, and their correspondent values returned by the FIFA API:
The FIFA API supports multiple languages. To keep things simple with this project, we will use only English. Next, we will create a dictionary where the key is the language localization, and the value is a list of strings that correspond to interesting match events:
You can add support to other languages (I’ve added Portuguese support to my bot).
Now, let’s write a generic get_url
function that takes in a URL and uses the python Requests library to make an HTTP request. This makes our code easier to customize, if you want to use it for other purposes:
We’re getting close! Let’s write a couple of helper functions that will actually call the FIFA API:
What is happening here? We wrote a function get_all_matches
that retrieves all the world cup matches, by calling the endpoint with the constants we defined at the top of our code. We use the json library method load
to decode the returned JSON.
The get_player_alias
function will be called when we need to identify a specific player. It returns a string with the player’s name.
Now that we have all the data we need, let’s find a way to store that data, so later on we can parse it and look for interesting events.
For the scope of this project, we will store the data in a .json
file, similarly to what we did previously with our subscribe.csv
file.
Let’s save our progress and create a new file on our terminal, where we will store data about on-going games:
Let’s get back to notifier.py
and finish up our work. Add the path to our JSON file where you declared the module’s constants:
We will write a function that we can call whenever we need to update our data file:
We will keep track of the last time we updated the data file by adding a Unix timestamp as a key-value pair. Here is a quick helper function to create the timestamp:
Before we call the FIFA API and parse the data, let’s make sure that we can send the interesting events we might find to Slack and to our SMS subscribers.
First, let’s write a function that sends a POST request to our Flask app:
This function will make a POST request to our updates endpoint and post the passed in text and attachment to all of our futbol fans.
Posting to slack is even easier: Go to the top of the file, where we added all the import statements, and import the post_to_slack
method from our slack_handler
module:
Add another constant that holds the name of the slack channel you’d like to post the updates to. Make sure that your bot is added to that channel.
The final piece of code you’ll have to write will handle calling the FIFA API and check if there are any live matches going on.
If there is one or more matches happening, for each live match, we make an API call to retrieve events.
Then, if any of the events retrieved match the interesting event constants, we will call the send_SMS
and post_to_slack
functions.
To test your notifier, open the worldCupData.json
file and paste the following:
Now, with your server.py
and slack_handler.py
running, open a new terminal and run the notifier (make sure to run when a game is NOT happening):
You should receive the updates from that match on the Slack channel you added to the notifier.py
(remember to add your Slack bot to it):
And if you subscribed, you should see the following messages:
Finally, check your WorldCupData.json
, it should look like this:
Ole ole ole!
As the last step, we will setup crontab to run notifier every minute, so we can offer real time updates on live matches. Windows users can check out Windows Task Scheduler. Run:
And add the following script:
Remember, you will have to keep slack_handler.py
and server.py
persistently running somewhere – or at least while a match is happening.
Wrapping up
It’s time to celebrate! You did it!
But there’s so much more you can do with Slack and Twilio APIs. Here are some ideas:
- Add emojis to your messages
- Implement a persistent backend like PostgreSQL and use it to store match events and subscribers
- The next World Cup will be in 2022. Until then, why don’t you create a new notifier to stay up to date with other championships or other sports?
Let me know what you come up with!
- Email: mbichoffe@twilio.com
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.