Building a Slack bot (is surprisingly hard)
Tags: showdev
Published: 2020-04-14 05:38:59

---
title: Building a Slack bot (is surprisingly hard)
published: true
description: Slack bot development 101.
tags: showdev
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/x9jfhjv2x5r3ovp8167z.png
---

A couple of weeks ago, I have entered a COVID themed hackathon organized by https://www.beondeck.com/.

My idea was simple:

> A lot of people are transitioning to WFH.
> They are used to staying in sync with their team through unplanned conversations that happen every day in the office (but don't happen online).
> I can ease their transition by creating a virtual medium for having serendipitous conversations with their team.

I decided to make a Slack bot since this is the tool that every team will be using already. It is just lacking that element of "water cooler" conversations.

I ended up building: [Snack](https://aboutsnack.com/), a sort of chatroulette for Slack (but without d*cks 🍆).

{% youtube QZTHjdb8Su0 %}

(Video shows slightly outdated user-experience. See https://aboutsnack.com/snack-club-channel)

What I didn't expect is just how complex this is going to be. I estimated it to be something I can turnaround over the weekend, but instead it ended up *over 70k lines of code*.

The user-experience is pretty simple:

1. Join `#snack-club` channel.
1. Type `/snack`.
3. Have a video conversation with someone else in your Slack workspace.

![Snack meeting experience.](https://dev-to-uploads.s3.amazonaws.com/i/5yly5yx3kwpymrw7o9q9.png)
(Snack meeting experience.)

But the complexity is behind the scenes.

If you are thinking of building something like this, here are some tips:

## Use a framework

Somehow it completely flew under my radar, but there is a Slack framework for building bots.

https://slack.dev/bolt/concepts

I didn't know about it and didn't use it. I only discovered the [Slack SDKs](https://slack.dev/node-slack-sdk/).

Knowing about Bolt would have likely saved a lot of time.

## How to host a video?

I have ended up using [Zoom](https://zoom.us/). They have a pretty thorough [API](https://marketplace.zoom.us/docs/api-reference/zoom-api). Using their API I was able to:

* [start video meeting](https://marketplace.zoom.us/docs/api-reference/zoom-api/meetings/meetingcreate)
* [end video meeting](https://marketplace.zoom.us/docs/api-reference/zoom-api/meetings/meetingstatus)
* subscribe to events about:
  * [event start](https://marketplace.zoom.us/docs/api-reference/webhook-reference/meeting-events/meeting-started)
  * [participant joined](https://marketplace.zoom.us/docs/api-reference/webhook-reference/meeting-events/participant-joined-meeting)
  * [participant left](https://marketplace.zoom.us/docs/api-reference/webhook-reference/meeting-events/participant-left)
  * [event end](https://marketplace.zoom.us/docs/api-reference/webhook-reference/meeting-events/meeting-ending)

The tricky part was to discover the availability of the webhook events: the data about participants is not available via API.

Note: I have later replaced Zoom integration with [Twilio WebRTC](https://www.twilio.com/video) as I needed more flexibility about the video experience.

## How to find which Slack users are present?

What would seem like a straightforward issue, turned out to be one of the biggest headaches. Turns out that Slack API [does not provide any scalable way to check if users are present](https://stackoverflow.com/questions/60908206/how-to-get-users-presence-using-slack-api).

I needed this functionality in order to identify who is available to _snack_.

I ended up asking Slack permissions to read list of workspace users and doing randomized checks every minute, i.e. every minute I pick 50 random users and I check their presence using the rate-limited [`getPresence`](https://api.slack.com/methods/users.getPresence) API. This works. It is strange that there are no events for user presence change, though.

## How to communicate with Slack users?

Slack API makes communication with the bot user a bit tricky. For every interaction, you have a [`response_url`](https://api.slack.com/interactivity/handling#message_responses) (a temporary webhook URL that you can use to generate messages responses). The keyword is _temporary_. It is also limited how many times you can use (5).

I had a requirement to "count down" as the video is about to end (the videos are capped to 15 minutes). Therefore the 5 request limit didn't work.

I ended up using a mix of:

* Only using `response_url` for the response to the first interaction. After the first interaction, I switch to one of the following methods. Otherwise, the unpredictability of `response_url` availability means that sometimes messages are not delivered.
* [Ephemeral messages](https://api.slack.com/methods/chat.postEphemeral) for introductions to the `#snack-club` channel, i.e. activities where I know that I already have users attention in a specific channel.
* [Regular messages](https://api.slack.com/methods/chat.postMessage) for important messages (e.g. meeting invitation)
* Threading meeting updates (e.g. count down) under the regular messages.

The tricky part here is that you will need to track identify attributes of all messages sent to the user in order to thread updates under them.

The rest of the complexity is app-specific (e.g. how do you match make, how do you handle feedback, how do you handle when people disconnect middle of the conversation, how do you handle when people do not respond in time, etc.) It was a fun project to build and it seems to be picking up some traction. There have been already over 400+ snack meetings and it is currently used by 23 Slack orgs. Who knows, maybe this will grow into something bigger than a hackathon project. For now, it has been an extremely fun project to build and test.

If you are going to give it a try, please contact me to test it together. I would love to get to know you and have your feedback.