Creating a Chatbot for Slack with Node.js in 17 lines

Creating a chatbot for Slack, the easy to setup group chat for teams was surprisingly easy. In this post we're going to go over creating a chat bot that can reply to queries and take an action on simple keywords.

We're going to use a node module called BotKit, which will enable us to connect to Slack easily. Actually Botkit offers a GUI (paid plans) and also connects to Microsoft Teams, Spark, Twilio and even Facebook.

One of the things I like the most about it is that you can kind of build a bot once and then re-use components across different platforms, which is super cool.

This post is written with

  • node 9.3.0

but will probably be up and downwards compatible fairly far since the dependency has been around for a while.

Setting up the Dependencies and the API Token

The only dependency we really need is botkit and an API token from Slack. Go ahead and create your project directory and inside it install botkit as a dependency:

npm init -y
npm install --save botkit

To get the slack API token, you need to be signed up with Slack and visit the Bot user page where you can view your API token. Copy this one or write it down, we're going to need it to create our bot!

You'll need to fill out a username for your bot

and will provided an API token.

Also you can either set a custom image or an emoji for your chatbot.

Writing the Minimum Viable Chat Bot in 5 minutes

The botkit repository has some examples for bots for slack, but let's start even shorter than that.

Let's create a file called step-1.js and insert the following code:

var Botkit = require('botkit');

var controller = Botkit.slackbot({
  debug: false
});

controller.spawn({
  token: "****-**************-*********" // your API key here
}).startRTM(function (err) {
  if (err) {
    throw new Error(err);
  }
});

controller.hears(['hello', 'hi'], ['ambient', 'direct_mention', 'mention'], function (bot, message) {
  bot.reply(message, "Hello.");
});

Now let's run node step-1.js which should produce the following output if it worked:

Initializing Botkit v0.6.7
info: ** No persistent storage method specified! Data may be lost when process shuts down.
info: ** API CALL: https://slack.com/api/rtm.connect
notice: ** BOT ID: gegenbot ...attempting to connect to RTM!
notice: RTM websocket opened

If something is wrong with your API key, it will give you an error message like so:

/home/jonathan/projects/GegenBot/step-1.js:11
    throw new Error(err);
    ^

Error: not_authed

Let's go back to the code for second.

controller.hears(
  ['hello', 'hi'], // trigger
  ['ambient', 'direct_mention', 'mention'], // context
  function (bot, message) { // callback (what to do?)
    bot.reply(message, "Hello.");
});

The controller code will determine the behaviour of our chatbot. Basically the function hears() has three arguments:

  1. Trigger: ['hello', 'hi'] (array)
  2. Location / Context: ['ambient', 'direct_mention', 'mention'] (array)
  3. The Callback - What is the bot supposed to respond or do? (function)

So the triggers are pretty simple, they're not exact matches, but basically if the combination of letters occurs, the bot will fire the function. This also means that if you build a badword filter and want to call people out for swearing the occurrance of anal will trigger when they just wrote analytics.

The location or context means: Where did the bot hear this?. Were they mentioned or did they just hear somebody say one of words in a channel?

  • ambient: the bot just heard it in a channel (for the fun gif commands)
  • direct_mention: the bot was mentioned with @gegenbot (or your bot name)
  • mention: the bot was mentioned by name
  • direct_message: your chat bot received a direct message with that trigger

Let's open our Slack app and see if our bot has arrived well!

Interacting with your Chatbot

If your chatbot has successfully made it to Slack, you should see it online in the sidebar under Apps:

For development purposes I recommend you create a bots channel, so you don't spam your co-worker with half baked code that basically doesn't work yet. Obviously such mishaps would never happen to me and it's purely a precaution ;)

Invite your bot to any channel with the /invite command in Slack. In my case I had to write: /invite @gegenbot, but if you start the username with an @, slack will offer you some autocompletion magic.

Basically in slack, like on IRC, channels are identified with a # and like on twitter and elsewhere @ signals a username.

Did you see I didn't directly match any of the words we had specified in our trigger array? That's because it automatically checks the lowercase version and responds anyways, even if I type Hello? instead of hello. If you want to match explicit cases, you should use a regex.

Where to go from here?

There are few limits. First off, get your API key out of your application code and put it in an environment variable like the official example tells you to.

Next off, write an amazing bot that calls co-workers out for swearing or asks people to be specific when they just end a sentence with "it." or "this." like:

I can't do this.
and the bot would go:
What is "this"?! Be specific please!
(Yes, I have seen people get red in anger over this, so maybe not a good idea.)

Or do a bot that's hooked up to your hacked coffee machine and remotely start brewing coffee from Slack! Hook it up to a ton of APIs, your imagination is the limit!

If you would like to read a couple of examples like:

  • crawl weather / bitcoin / stock data from a website and output to chat
  • adding a random gif pool
  • enforcing a bad word filter

Just let me know in the comments or hit me up on twitter!

Tagged with: #Botkit #node.js #Slack

Thank you for reading! If you have any comments, additions or questions, please tweet or toot them at me!