Nic Rosental / Development / May 6th, 2016

Taking Our First Slack App Out to Lunch

Like any development shop, we go out to lunch between head-down coding sessions. Over the last couple of weeks, our Product Team has been busy working on /Lunchbox – a simple, but powerful, Slack bot to simplify organizing a lunch outing with colleagues.

As much as we love Slack for communicating between our teams, clients and offices, it’s also a new development platform (we’re always on the lookout for a new sandbox to play in). While /Lunchbox has made our daily lunch groups a much simpler exercise, it was also an exciting opportunity for our product developers to get their hands dirty with Slack.

Before we explore the nerdy details of using the Slack API, this is a good opportunity to tell why we were so focused on building /Lunchbox. Earlier this year, we transformed our digital marketing teams into a product growth department, focused on bringing internal products like MixFrame and to market. We also want to launch 5 new products from this team in 2016 – /Lunchbox is the first.

Fair warning: this will be a technical post full of development tips, but if you’re looking for detailed instructions on building for Slack, I recommend starting here.

As with any greenfield project, we had the luxury of choosing our technology stack with minimal constraints. We settled on the trusty MEAN stack due to how well-suited it is for real-time applications, the availability of high-quality packages for the Slack API, and our prior experience with the technologies involved. Other important tech bits were Gulp (with Nodemon) for our local development setup, Heroku for hosting, Git + Github for version control, and a few NodeJS modules – more on those later.

How do Slack integrations work?

Our daily use gave us a vague idea of what the Slack API offers, but it was time to do a deep dive and really discover its capabilities. At present, Slack uses several distinct APIs which can be combined to accomplish complex integrations: webhooks, commands, RTM, Web API, and bot users. Once we understood what each of these offerings delivered, we decided our application would need commands and bot users.

Slack commands are easy enough, as most users know. A command phrase (preceded by a slash) triggers an action without showing the command: spam your channel with a storm of GIFs, check for certain data or give a shrug ¯\_(ツ)_/¯. In our case, we picked /lunch.

Bot users make Slack and its integrations tick. Bots can do pretty much everything a human user can do, which makes for a great opportunity to imbue the application with its own personality. We wanted our Lunchbox bot to be fun, but also useful.

By now we had picked our technologies, determined the APIs we needed, and decided how the application would work.

Putting the pieces together

The first step in a Slack integration is requesting permission. Slack uses OAuth 2.0. The implementation is very clean, and it’s made very easy with the use of the Slack Button.

lunchbox screen
Before requesting authorization, determine the scope of the permissions needed. Scopes can be broad or very detailed, but it’s important to make sure to understand which scopes are strictly needed and not ask for more than that. It’s poor form to be greedy, but it’ll also prevent you from getting listed in the Slack App Store. In our case, we settled on the bot and commands scopes, two broad options encompassing many other, smaller permissions.

Once a user adds the integration to their Slack team, the API responds with a JSON object:

	"team_id" : "T0XYZXYZX",
	"bot" : {
		"bot_access_token" : "xoxb-12345678900-1uDw3VvfRes2QaaRfc8EesWr",
		"bot_user_id" : "U0IDSE4T6"
	"team_name" : "352 Inc",
	"scope" : "identify,bot,commands",
	"access_token" : "xoxp-1234567890-1234567890-1234567890-8f3ed42f9o",
	"ok" : true

Store this information, otherwise the integration won’t be able to interact with Slack. Most of the items are self-explanatory, but I’d like to point out the access_token, and bot_access_token. The former is the authorization for the application itself to work with that particular Slack team, while the latter is exclusively for the bot user to perform actions such as posting a message to a chat, creating a channel, etc.

lunchbox slack commandsNow that the application has been authorized, the integration is live. In our case, we wanted to respond to the slash command /lunch. The initial step is to set up the command in our application dashboard. You’ll notice the Command editor is pretty straightforward.

Here we can enter the command to respond to, where the request is going to be sent to, a description and a usage hint. The usage hint is optional – we strongly suggest you include it. Bots are simple, but users will have an easier time using your integration with a little bit of UX focus.


Command Functions

While Commands are fairly easy to set up, you should know what’s going on behind the scenes. Once a user issues a command, all the data for that command gets sent formatted as JSON, via a POST request to the Request URL specified in the dashboard. This address must be SSL encrypted, and Slack must be able to reach it.

This represents a challenge when developing locally. Thankfully, there are excellent tunneling services that make setting this up dead simple. We picked Ngrok and it’s been rock solid. Start Ngrok by issuing a simple command like ./ngrok http localhost:5555 (where localhost:5555 is the address our NodeJS app is running on) and you’ll get a tunnel that serves your application through http and https to the world.

lunchbox ngrok

In this case, we could tell Slack to send requests to Now that the tunnel is up and Slack knows where to submit requests , you can start building the bits that will receive, parse and respond to the message.

In this example, the Midtown Atlanta user typed /lunch at Cypress, F20 or Takorea at 12:30. This is what you can expect to receive in your application’s endpoint:

lunchbox ngrok 2

In your Express app, you could set up a route like the following:'/commands/lunch', function (req, res) {
	// do something with req.body here
	// send a reply to the channel
	res.send('Look, Ma! I can reply!');

The message Look, Ma! I can reply! will be sent back in what Slack calls an ephemeral message, which means it’s a message that only the user issuing the command can see. This is useful for sending error messages or responding to help requests. No need to publish those things to everyone in the channel.

If you don’t send a reply, at the very minimum an http status code, Slack will throw a timeout error, so make sure you don’t leave any unresponded endpoints.

slackbot lunchbox

Enter the Bot – beep boop

Now that we have the command loop in place, we can bring in the bot into the mix. In our case, we want to parse out restaurants – along with optional times and dates – from the command, build a message that offers one emoji per restaurant (for group voting), and then respond with the message asking people in the channel to join our lunch outing.

We won’t bore you with the details about parsing the message, and instead we’ll go straight into the response. In this case we don’t want to respond directly to the command, but instead, we want our bot to post the message as itself, and make it visible to everyone in the channel.

To make our lives easier, we decided to use the very simple Slackbots.js module.

The code for posting the message looks something like this:

bot.postMessage(channelId, message).then(function(data){
    // do some other stuff here.

As you imagine then() means a successful message. You can also work with fail() and always(). In this case data contains the result of our successful message.

{ ok: true,
channel: 'ABCD1234',
ts: '1460488064.000030',
{ text: 'some message text that was sent by Lunchbox',
	username: 'lunchbox',
	bot_id: 'B01234AEVT',
	type: 'message',
	subtype: 'bot_message',
	ts: '1460488064.000030' } }

Our next step is to provide the reactions we want to use for people in the chatroom to vote. The key here is the ts entry. Messages in Slack use their timestamp as a unique identifier (as opposed to files, and file comments which have IDs).

To post a reaction to a message, we use the Web API endpoint reactions.add. In this case, we decided to use a simple http request and no libraries. This is entirely up to you, but it’s as simple as constructing the right URL and making a POST request to the endpoint. The following is an example of a URL that would send the :thumbsup: reaction to the message above.

Note that we are using the bot token ID, so the reaction will be posted by the bot user itself. This is useful so the person issuing the command can vote on the options without un-doing them.

At this point we have all the building blocks that make the application work. Next up, you’ll need to deploy it to a publicly accessible host. In our case, we chose Heroku. If you are using Heroku, you’ll want to work above the free tier plan, otherwise your app will go to sleep and users won’t be able to enjoy it.

Spreading the love

We now had a nice integration for ourselves, but we definitely wanted to share our handywork with the rest of Slack world. The first step was to have our own website where users could learn about /Lunchbox, and also install it.

By default, any user can add an integration to their Slack team. The best way to enable them to do so is the Slack button. Of course, you’d need users to find you, and what better way to do so than having the app listed in Slack’s own App Directory.

The process of submitting the app for review was a breeze, and the Slack team was very fast, and attentive throughout the process. In less than two weeks we had our app listed, and ready to schedule lunches the world over.

Build something cool, follow this checklist, and submit.

Wrapping up

Given its wide use in dev shops and rapid rise, it’s no surprise the Slack API is so well constructed. Although we ran into some challenges at times (figuring out message IDs, working locally, etc.), we were able to quickly and easily overcome them, and finish our application in a fairly short time. Expect to see new features for /Lunchbox in the near future, as well as many other bots.

Are you ready for lunch? Check us out in the Slack App Store, and make sure you invite your colleagues.