Slack Bot Hacks (2019)

Slack Bot Hacks

Slack Bots

Bots are where Slack and its integrations really come alive. They allow you to build advanced functionality right into a chat application, giving sometimes complex code an easy-to-use and familiar interface.


In this blog, you will learn how to host chatbots on Google Cloud Functions and integrate it with your Slack team.  And then explains how slack bot integrates with AWS Lambda.


Bots appear in Slack as users in the team directory. They have the ability to read and write to conversations, they can be invited to channels and private groups, and you can interact with them via direct messages.


 The most popular bots include Errbot and Hubot. These bots run independently of Slack and can be extended and customized to cater to the needs of a team.


For example, Errbot can organize tournaments for your team or generate graphs in conversations. Hubert can interact with Trello or return Google PageSpeed results.


Let’s get started with some hacks that tap into the Slack APIs.


Use Google Cloud Functions as a slash command endpoint

Slash commands in Slack are shortcuts that users can type to send an HTTP request to a server. The users don’t need to know all of the details about which server to call and how to pass parameters, they just type /commandName with some arguments and Slack does the rest, returning the answer from the server.


In this hack, you will learn how to host a slash command endpoint using Google Cloud Functions and integrate it with your Slack team. Google Cloud Functions is a feature available in the Google Cloud Platform, a cloud hosting solution offered by Google.


Using the Google Cloud Platform allows you to integrate your hosted projects seamlessly with Google’s API. This is done using Google Maps’ features like generating a custom map image or fetching a YouTube video stream. Google Cloud Functions are a very simple way to deploy a slack slash command endpoint on the web.


If you don’t have yet a Google Cloud Platform account, you will have to create one for free using the URL given above. On the project you will create to host the endpoint, you will need to enable the Google Cloud Billing API.


Since Google Cloud Functions is still in alpha stage, you must perform the following steps to enable its use on your project.

  1. First, perform the five first steps of the
  2. At the time of writing, cloud functions are pretty new, so you’ll have to go to the API manager to activate the API.
  3. Then use cloud init to authenticate and select the project on which you want to deploy your function.
  4.  Functions at this point are in alpha, so you can add them to cloud by typing: cloud components install alpha. 


For the latest full release notes, please visit:

Do you want to continue (Y/n)?


Once you’ve performed those steps, create a working directory:

$ mkdir ~/slack-function

$ cd ~/slack-function


And then create a bucket to store your code. The name of the bucket needs to be globally unique:

$ gsutil mb gs://[BUCKET_NAME]


Now that your function is ready, you can deploy it to be triggered via HTTP:

$ gcloud alpha functions deploy slackhello --bucket [BUCKET_NAME] \


Copying http://file:///tmp/tmpbr_Zen/ [Content-Type=application/zip]... Uploading ...ns/ 689 B/689 B Waiting for the operation to finish...|


Carefully note the given URL. If you lose it, you can get it back querying the fucntion like this: $ gcloud alpha function describe slackhello


Now, try your function to see if it is ready before trying it with Slack:

$ curl -X POST <HTTP_URL> --data '{"message":"Hello World!"}'


You are now ready to hook your function up to Slack! In your channel, click on the gear and then choose “Add an app or integration.” Then in the search box type “command” and select Slash Commands


Next, name your slash command so you can assign it to your Google Cloud function

Then hook your slash command up to the URL of your Cloud Function via the URL field of the slash command settings. Be sure to fill in the Autocomplete help text field in the settings to add your slash command in the autocomplete list.


Use an AWS Lambda to host a slash command endpoint

Amazon Web Services’ Lambda is a nice alternative to Google Cloud Functions. It hosts your code on Amazon’s cloud so you can focus on your code and delegate the hosting duty to Amazon Web Services.


Using Lambda is a simple way to host a Slack slash command endpoint. Amazon has even provided a blueprint for doing so. In your AWS console, go to the Lambdas section and create a new Lambda from the slack-echo-command-python blueprint.


Then replace the template version with this simpler version:

import logging
logger = logging.getLogger() logger.setLevel( -&nbspThis website is for sale! -&nbspLogging Resources and Information.)
def lambda_handler(event, context): user = event['user_name'] command = event['command'] channel = event['channel_name'] command_text = event['text']
return "%s invoked %s in %s with the following text: %s" % \ (user, command, channel, command_text)


On the lambda endpoint, select “POST” as the method and set security to “Open”

Next, click on the API endpoint to go to the API gateway


Once the API gateway screen appears, click on the lambda, then the API endpoint, then POST to show the method execution

At the bottom of the method-execution diagram screen, click “add mapping template.”


This transformation is the magic behind the lambda code that transforms the POST data content encoded in application/x-www- form-urlencoded into JSON structured data, which is easier to manipulate. 


Make a calculator with Google App Engine

Google App Engine is a platform-as-a-service (PAAS) that simplifies greatly the deployment and maintenance of a web-based service (Like Heroku or Amazon Web Services). This is exactly what we need for a Slack bot. In this hack, we will show you how to make a simple calculator with a Slack Slash command in Go. 


Make a new application on App Engine

You’ll need to open an account on the Google Cloud Platform and start a project. 

Once you have created a project ID, write its name down, since it will be useful later. You can also see the project ID in the drop-down menu on the top right of the Google Cloud Platform. 


Next, you need to install the Go language App Engine SDK from You can check whether your SDK is correctly installed by typing app version.


Configure the slash command in Slack

Now let’s configure a Slash command in Slack to handle our little calculator using techniques similar to the ones we used in Hacks #22 and #23. Enter the following in the Integrations Setting screen

  • Command: /calc.
  • URL:
  • Method: POST
  • Token: This will be generated for you
  • Customize Name: calculator
  • Autocomplete help text: Select /feedback, turn on the “Show this command in the autocomplete list” checkbox.
  • For the autocomplete description, we used “Calculate some-thing” and our usage hint is “/calc 2+3*(5-7)”.


Code and structure

You need to create the following files and directory structure:

├── app.yaml

└── calc

└── cmd.go

The app.yaml file is an App Engine descriptor that sets up the run-time and serving parameters for your application. You can find the official documentation for this file here:


Enter the following code in app.yaml:

application: slashcalc version: 1

runtime: go api_version: go1

handlers: - url: /.* script: _go_app


Next, we are going to define the logic of our command. The entry point is a handler, which will be called every time an HTTP request lands on your application.


The slash command will post a form with parameters like “text” that we will use to get the parameters the user gave to the command in the Slack chat box. The remaining code is pretty standard with some formatting and error handling.



In order to keep the example simple, it doesn’t deal with any security. For example, we recommend that you match the security token you define in your Slack command from the handler function to be sure the request comes from Slack and not any third party on the Internet.


Here’s the Go code of the calculator we will deploy on Google App Engine:

package calc
import (
"" "net/http"
func init() {
http.HandleFunc("/", handler)
const PAYLOAD string = `
"response_type": "in_channel", "text": "= %s"
// Strip trailing zeros from a float
func formatFloat(num float64) string { str := fmt.Sprintf("%.9f", num) truncate := len(str)
for i := len(str) - 1; i >= 0; i-- {
if str[i] == '0' {
truncate = i
if truncate > 0 && str[truncate-1] == '.' { truncate--
return str[0:truncate]
func handler(w http.ResponseWriter, r *http.Request) { args := r.FormValue("text")
lexer := lib.Lexer(args)
interpreter := lib.Interpreter(&lexer) result, err := interpreter.Result()
if err == nil {
w.Header().Set("Content-Type", "application/json") fmt.Fprintf(w, PAYLOAD, formatFloat(result))
} else {
fmt.Fprintf(w, "ERROR %s [%s]", err, args)

For this example, we used a pre-built calculator parser library that you can find at ryandao/go-calculator. 

In order to install this library so App Engine can deploy it, you simply run the following command:

$ goapp get


Testing locally

Before deploying your application, you can use App Engine’s dev app server feature to test it locally. To start a little local server with your code deployed on it, you can use soap serve from the root of your application (where app.yaml is):

$ goapp serve

INFO 2016-06-07 06:08:40,109]


Skipping SDK update check.

  1. INFO 2016-06-07 06:08:40,173]
  2. Starting API server at: http://localhost:45511 INFO 2016-06-07 06:08:40,175]
  3. Starting module "default" running at: http://localhost:8080 INFO 2016-06-07 06:08:40,176]
  4. Starting admin server at: http://localhost:8000
  5. To test your application, give it an expression within the URL, such as http://localhost:8080/?text=3*2


URL encoded format for + symbol

The text parameter needs to be URL encoded and + is a character used in the encoding grammar, so if you want to try out + you will need to use %2B instead.


Deploying on App Engine

This is where you’ll need your project ID from the cloud console. We used fizz-buzz-314 here, but you’ll need to replace that with your actual ID. Use this command to deploy the application:

$ goapp deploy -application fizz-buzz-314 app.yaml [...]

Once it is deployed, you can test the application independently from Slack. Notice that the URL includes both https and the name of your project


You can then try your application in Slack

You can use this example as a base for your own project or by analogy for any other language available on the App Engine (Java, PHP, Python).


Host a poker bot with Heroku

Heroku is an easy to use platform-as-a-service, and hosting a Slack bot on it is really simple. As an example, in this hack, we will see how to use it to run the poker bot from This hack requires a Heroku Slack bot using Node.js.


Create a bot integration

First, create a bot user for your team via services/new/bot, where TEAM is the name of your Slack team.

Then fill in the API Token, Customize Name, and optionally upload a Customize Icon field on that web page


Install a local Heroku environment

 In a nutshell, if you want to install the toolbelt on your account on Linux do the following:

$ cd
$ wget\ heroku-client/heroku-client.tgz
$ taz xzvf heroku-client.tgz [...]
$ mv heroku-client heroku


Then add the ~/heroku/bin to your latex-math:[$PATH environment variable in your /.bashrc or /.zshrc by adding the line export PATH=$]\{HOME}/heroku/bin:$PATH.


You can then use the following command to log in to your Heroku account.

$ heroku login

heroku-cli: Installing CLI. 22.7MB/22.7MBB


Enter your Heroku credentials. Email: gbin@domain.tld

Password (typing will be hidden):

Logged in as gbin@domain.tld

Deploy the project on Heroku

First, clone the code repository:

$ git clone
$ cd slack-poker-bot
Then create a Heroku App from the root of this Git repository:
$ heroku create
Creating app... done, ⬢ mighty-tundra-99867 | \
If you run git remote -v, you’ll see that heroku create effectively added a new remote to your local Git clone:
$ git remote -v [...]
heroku (fetch) heroku (push) [...]
Then set your bot’s API token:
$ heroku config:set SLACK_POKER_BOT_TOKEN=\
xoxb-48370906999-nF40aVh2hM76Ub0LWCtiripm Setting SLACK_POKER_BOT_TOKEN and restarting ⬢ \
mighty-tundra-99867... done, v3
SLACK_POKER_BOT_TOKEN: xoxb-48370906999-nF40aVh2hM76Ub0LWCtiripm
You can now deploy your bot like so (note that this may take a while).
$ git push heroku master Counting objects: 1211, done.
Delta compression using up to 4 threads. Compressing objects: 100% (465/465), done.
Writing objects: 100% (1211/1211), 5.43 MiB | 88.00 KiB/s, done. Total 1211 (delta 733), reused 1211 (delta 733)
remote: Compressing source files... done. remote: Building source:
remote: ----> Node.js app detected remote:
remote: ----> Creating runtime environment remote:
remote: NPM_CONFIG_PRODUCTION=true remote: NODE_ENV=production
remote: NODE_MODULES_CACHE=true [...]
remote: Verifying deploy. done.

To * [new branch] master -> master


Invite and use the bot

At the top right of your Slack window, click the gear icon and choose “Invite team members to join…”

Select the newly created team member that should be online by then.


You can now ask the dealer to deal by typing @dealer: deal; after that, all of the players wanting to play need to respond yes. Once they’ve done so, the game can get started, and the bot will message you in private about your hand. You may now have some ideas for creating and hosting your own games on Heroku!


Create a bot to randomly select someone for a task

In this hack, we’ll build a PHP script which, when called, will pick a random person who is both a member of the Slack channel from which it was called and is currently online. The purpose of this particular script is to randomly select someone to make tea, but the same tool can be used to distribute other tasks around the office.


In this hack, you’ll learn the basic mechanism for triggering scripts and targeting specific members of a channel. Once you know how to do that, you can let your imagination run free and create all sorts of solutions.


Hosting this hack

Consider hosting your PHP script on Google App Engine or on Heroku. The steps for this script, which can be found on Github are:

  1. Trigger from a channel
  2.  Get the members in that channel
  3. Filter out the offline members
  4.  Filter out any from the exclusion list
  5. Select a random online team member for tea making

The first step is to get Slack to call your script and to return something. To do this, you need to add an outgoing webhook to your team.


Add an Outgoing Webhook for the !tea command

1. Go to the Outgoing Webhooks page and click “install for your team”.

2. Click “Add Outgoing Webhooks Integration”.

3. Fill in the fields as follows:

  1. Channel: Any (or your dedicated Tea channel).
  2. Trigger Word(s): !tea.
  3. URL(s): The URL where your script will be (make sure it is a PHP file and publicly accessible).
  4. Descriptive Label: Whatever you want.
  5. Customize Name: Tea Bot.
  6. Customize Icon: Click “Choose an emoji” and select the tea icon

4. Click Save.


Picking an active user

To select a random user to prepare the tea, we need to select one among all the users that are active in the channel the command was sent on.


Through its Web API, Slack provides a method for getting information about a channel: Among this information is the channel members, so you can call it to get a list of the members’ IDs.


To convert IDs to names, use another Web API method that gives you information about a user from an ID: From this call, we will be able to get the username in order to determine who should be excluded from the tea making duty.


Finally, we will need to determine each user’s presence by using the users.getPresence Slack API method and filter out the inactive users. The active member users will then be added to a new $teaMak ers array.


From this array, a random team member can then be picked to make the tea using the pickOne function whose purpose is to pick a random element from an array of elements.


Here’s the script that performs all of these tasks:

// Get the info for the channel requested from
$data = $Slack->call('',
array('channel' => $_POST['channel_id']));
$teaMakers = array();
// Loop through channel members
foreach ($data['channel']['members'] as $m) {
// Get user data
$userData = $Slack->call('', array('user' => $m));
// Check to see whether the user is online before adding
// them to list of brewers
$presence = $Slack->call('users.getPresence',
array('user' => $m));
$user = $userData['user'];
// If there is an exclude, check to see if it matches
// a user's real name (lowercase)
// If it doesn't, add it to the $teaMakers array
if($presence['presence'] == 'active')
$teaMakers[] = $user;
function pickOne($array) { shuffle($array);
return $array[rand(0, (count($array) - 1))];
$user = pickOne($teaMakers); header('Content-Type: application/json');
echo json_encode(array( 'text' => $user['id']


This script returns a user ID, which isn’t very helpful to anyone. To fix that, instead of returning $user['id'] in json_encode, you can return $user['name']. This tells you whose turn it is in human-readable form. 


The other option is to return the ID as a link to the user. This approach then, not only returns the username but also notifies the user of their duty.


To build a link to a user in Slack, add a <@ in front of the

$user['id'] and a > after it; for example:
header('Content-Type: application/json');
echo json_encode(array(
'text' => '<@' . $user['name'] . '>'


Allow exclusions

The last step in building the tea bot is to allow exclusions to be passed in. Using the $_POST['text'] key, you can exclude the trigger word and exclude the correct users. 


Once you’ve isolated the exclusion text, you need to check to see whether the user matches the exclusion string; here’s the code that does that:

if($presence['presence'] == 'active')
if($exclude) {
if(!(strpos(strtolower($user['real_name']), strtolower($exclude)) !== false))
$teaMakers[] = $user;
} else {
$teaMakers[] = $user;


If the exclusion string is present, but the user doesn’t match the exclusion string, you still add them to the teaMakers array. You also convert everything to lower case when comparing, to remove any capital discrepancies.


 Your script should now pick a random, online member to get up and put the kettle on. Remember, everyone can see what you type and input into the webhook, so you won’t be able to get away with always excluding yourself!


Add a greeting to the tea bot

Now that the script is complete, you can add a nice greeting.

Being able to pick a random index from an array lets the bot make decisions; this will allow it to pick both the user and the response to use.


The following PHP script is the part of the tea bot that specifies an array at the top of the script and then, using a custom function, picks a random response:

<?php // Specify an array of responses $responses=array( 'Hello!', 'How are you?' 'How is your day going?' 'What do you call a chicken on roller skates? 'Poultry in motion!' ' ); // Random picking function function pickOne($array) { shuffle($array); return $array[rand(0, (count($array) - 1))]; } // Return a random response header('Content-Type: application/json'); echo json_encode(array( 'text'=> pickOne($responses)


This code snippet specifies responses in a simple PHP array, which is used for our tea bot.


Add some personality to the tea bot

An extra, optional step is to give your tea bot a little bit of personality. The following bit of code creates an array of random responses with a {{USER}} marker. Upon picking a victim, the tea bot uses this code to choose a response and substitute the marker with the selected marker.


First, create your array. For each entry, make sure the marker

{{USER}} is present. Then assign it to the variable $responses, like so:
$responses = array(
"It's about time {{USER}} put the kettle on - off you trot!",
"Pop the kettle on {{USER}} - it's your turn to make a cuppa",
"Who wants a drink? {{USER}} is heading to the kitchen to make one",
"Coffee? Tea? Sugar? Peppermint Tea? Green Tea? Get your orders in as {{USER}} is making a round",
"That's very nice of {{USER}} to make a round of tea!", "Mine is milk 2 sugars please {{USER}} - what about
everyone else?",
"The tea maker is... {{USER}}! Get brewing."

From this array, we can use the pickOne function to choose a random response, replace the marker with the actual user, and return the response using str_replace.

str_replace is a built in PHP function that has three parameters:
$what_to_replace_it_with, and $what_to_search_in). More details can be found on the PHP website.


Here’s the script choosing a random user and substituting {{USER}} for the designated user (the tea but will now be able to share random responses in Slack):

// Get a random user from the array

$user = pickOne($teaMakers);

// SEND OUT THE JSON!! Enjoy your brew header('Content-Type: application/json'); echo json_encode(array(

'text' => str_replace('{{USER}}', '<@' . $user['id'] . '>', pickOne($responses))



You have now successfully created your tea bot. Enjoy! Create a Slash command for posting anonymous messages to a channel


In this hack, you will learn how to implement a slash command in Golang and deploy it using Docker. When you activate the slash command /anon Who am I ? a message will be posted to a pre-selected channel.


The message will have a randomly selected avatar along with a quote. The avatar makes the user who sent the slash command anonymous since his message is posted without his name and avatar.


This hack can be a source of fun if several people use this slash command since multiple avatars can be created by multiple Slack users to send random messages, as detailed in the Loading the avatars section below.


 This hack is purely for fun, although as you will see, there’s a lot going on behind the scenes. The source code for this slash command can be found on Github.


Add a Slash command

  1. To create this slash command:
  2. Go to the Slash Commands page and click Add Configuration.
  3. Click “Add Outgoing Webhooks Integration”.
  4. On the page that appears, fill in the command name, e.g. /anon, and then click “Add Slash Command Integration”
  5. Leave the URL field empty.
  6. Set the method to POST.
  7. Write down the content of the Token field.
  8. In the Description field write “Send anonymous messages”.
  9. Click “Save Integration”.
  10. Go to the Incoming webhooks page.
  11. Click “Add Configuration” and copy the webhook URL
  12. Click “Save Settings”.


Setting up a server

In order for Slack to respond to your new slash command, you need to set up web servers that will accept the request from Slack after someone enters the command. In Go, each source file can define its own init function to set up whatever state is required. 


This means init is called after all of the variable declarations in the package have evaluated their initializers, and those are evaluated only after all the imported packages have been initialized. In our init function we will set the HTTP server port to 5000.


In the main function, we initialize a random number generator. We will get from the environment two variables:

  • The channel that we would like to post to.
  • The Slack token in order to validate requests.


The next step is to load the avatars from a JSON file. Once the loading is complete we will set up a handler function for the / path, and then the HTTP server will start.


Here’s the Go code that performs the steps we just described:

func main() {
rand.Seed(time.Now().UnixNano()) channel = os.Getenv("SLACK_CHANNEL_ID")
token = os.Getenv(tokenConfig) getAvatars()
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { result := readAnonymousMessage(r)
fmt.Fprintf(w, result)
http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
func init() {
//Init the web server port 5000
flag.IntVar(&port, "port", 5000, "HTTP server port") flag.Parse()


Loading the Avatars

Avatars are loaded from a JSON file, avatars.json, which is located at the same directory as our binary. We have defined The JSON object structure for an avatar as follows:

  • username - The user from which the message will be sent
  • default_text - A text that appears next to the avatar’s name
  • icon_url - The user avatar url


Here’s an example for a given avatar using this JSON structure:

"username": "Archer",
"default_text": "Phrasing!",
"icon_url": ""
The following code does two things:
1. It reads the JSON file.
2. It then populates three global arrays with the data from the file.
func getAvatars() []Avatar {
raw, err := ioutil.ReadFile("./avatars.json")
if err != nil { fmt.Println(err.Error()) os.Exit(1)
var c []Avatar
json.Unmarshal(raw, &c)
for _, p := range c {
avatars = append(avatars, p.Username) avatarIcon = append(avatarIcon, p.IconURL) avatarText = append(avatarText, p.DefaultText)
return c


Getting a message from Slack

When users issue the /anon slash command, the Slack server will perform a POST request to our server. We will handle this request in the readAnonymousMessage function.


First, we will try to parse the data that we received. We will compare the token that we received to the one from the environment variable in order to make sure that the request is legit. The next validation is to make sure that there is an actual text to send. Finally, we will trim spaces and send an anonymous message.


Here’s the code that performs these tasks:

func readAnonymousMessage(r *http.Request) string { err := r.ParseForm()
if err != nil {
return string(err.Error())
if len(r.Form[keyToken]) == 0 || r.Form[keyToken][0] != token {
return "Config error."
if len(r.Form[keyText]) == 0 {
return "Slack bug; inform the team."
msg := strings.TrimSpace(r.Form[keyText][0])
err = sendAnonymousMessage(msg)
if err != nil {
return "Failed to send message."
return fmt.Sprintf("Anonymously sent [%s] ", msg)


Sending the anonymous message

To send the anonymous message, the code has to perform these steps:

  1. Get the Slack webhook from the environment variable using os.Getenv function.
  2. Generate a random avatar ID using the rand. Intn function.
  3. Construct the message payload in JSON. The JSON structure for posting a message on a channel is available on the official Slack API documentation.


Here’s the Go code that performs these steps:

func sendAnonymousMessage(message string) error { url := os.Getenv(webhookConfig)
avatarID := rand.Intn(len(avatars)) payload, err := json.Marshal(slackMsg{
Text: message, Channel: channel, AsUser: "False",
IconURL: avatarIcon[avatarID], LinkNames: "1",
Username: fmt.Sprintf("%s : %s", avatars[avatarID],
if err != nil {
return err
_, err = http.Post(url, "application/json", bytes.NewBuffer(payload))
return err

We are now ready to send the anonymous message via the webhook URL.



Now, you can run the server inside a Docker container that can be deployed to your favorite cloud provider. A prebuilt binary Docker image can be found at Docker Hub.  Here is the Dockerfile used to build this Docker image:

FROM rounds/10m-build-go RUN apt-get update && \ apt-get install wget
RUN go get
RUN wget -O /root/go/bin/avatars.json \
CMD cd /root/go/bin/ && ./annona


The preceding code starts with a minimal base image. Then, we make sure that all packages are up to date and we use the standard go toolchain to fetch and build our Annona binary with go get.


After downloading the necessary avatars file using wget, we finally run the binary. You now can run Docker and pass in the following three environment variables:




Here’s the command line to do so :

docker run -e INCOMING_SLACK_WEBHOOK='<your webhook URL>' \
-e SLACK_CHANNEL_ID='<channel id where to post messages>' \
-e INCOMING_SLACK_TOKEN='<Slack token obtained when configuring the slas -p 5000\ <your_image_name>


Make sure to map the Docker port (5000) to a port at the host with the -p flag to Docker. After you deploy, make sure you go back to the URL at the slash command configuration page, and fill in your server address and port. You have now seen some simple, custom-made applications you can integrate into Slack.