Building a Slack Bot using Node.js (part 1)

Andy Aguilar
CodeX
Published in
7 min readJul 9, 2021

I recently built a slack bot using Node.js, Express, PostgreSQL, and Sequelize. I spent a lot of time learning to use those technologies and playing with the slack api. The process of learning to use all of those technologies was tedious (albeit educational), so I decided to write this series of blog posts so that you can get up and running while avoiding the hours spent researching.

To build a slack bot, you’ll need the following things:

  1. Node and npm installed on your computer.
  2. ngrok installed on your computer (this allows you to forward events that occur on your slack workspace to a localhost server for development)
  3. (Optional) PostgreSQL installed on your computer (we actually won’t get to this until part 2).

Okay! Let’s get started!

The first few steps of this guide will go over how to set up your initial file structure and dependencies. If you don’t care and just want to get yourself up and running, just fork and clone this GitHub repo and skip steps 1–4.

If you want to build up your project from scratch, follow these steps:

Step 0: Check your authorization

First make sure you are authorized to create an app in your workspace. Go to this link, and click Create New App. Click on the from scratch option and a modal will open that has an input for your app name and a select a workspace dropdown. Click on Select a Workspace and make sure you see the workspace you want to add the app to in that list. If you don’t see it either ask your workspace’s admin for access, or just create a new workspace where you can build/test your bot (moving a bot from one workspace to another is easy).

Give your app a name, select the workspace, and click Create App. Keep this tab open or bookmark it (we’ll need it for step 6).

Step 1: Create a project folder

Open your terminal, navigate to the folder where you want to keep this project, and use mkdir to create a new folder for this project. Open the folder you created in your preferred code editor. Then run npm init to initialize an npm project. This command will allow you to set attributes for this project including its name, version, description, etc… You can set these values to whatever you want, but I like setting the entry point to app.js (the default is index.js). You can always change these values later.

Step 2: Create some files

Create the following files:

app.js
.env
.gitignore
README.md

Open the .gitignore file and add the following code (along with anything else from this project that you don’t want added to github):

/*.env
/node_modules
.DS_Store

Step 3 (optional): Set up your GitHub repository for this project

Run the following commands from your terminal:

git init
git add .
git commit -m “First commit”

Go to GitHub.com and login to your account. On the left side of the screen you should see this green icon:

Click on it to create a new repository. Give it a name and a description, then click Create Repository. On the next screen copy the code under ...or push an existing repository from the command line . It should look something like this:

git remote add origin git@github.com:your-github-username/repo-name.git
git branch -M main
git push -u origin main

Step 4: Set up dependencies

From your terminal run npm install. Then run the following commands:

npm install express --save
npm install dotenv
npm install @slack/events-api
npm install @slack/web-api
npm install --save-dev nodemon

Open your package.json file and add the following to the "scripts" section:

"start": "node app.js",
"dev": "nodemon app.js"

This will allow you to run app.js whenever you run npm start and will allow you to use nodemon (which restarts server anytime you save changes to a file in the project) when you run npm run dev.

Step 5: Set up your app.js file

Open your app.js file and add the following code:

require('dotenv').config({path: __dirname + '/.env'})
const express = require("express")
const app = express()
const PORT = process.env.PORT || 3000
//YOUR CODE HEREapp.listen(PORT, () => {
console.log(`App listening at http://localhost:${PORT}`)
})

This sets up an express server that runs on localhost:3000 (unless you set a PORT in your .env file, which I’ll discuss in a later post).

To test that everything is working run npm start and you should see something like this:

> your-app-name@your-app-version start
> node app.js
App listening at http://localhost:3000

Close the server with ctrl-c, then run npm run dev and you should see:

> your-app-name@1.0.0 dev
> nodemon app.js
[nodemon] 2.0.9
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node app.js`
App listening at http://localhost:3000

Once you have both of those working, let’s connect this thing to slack.

Step 6: Set up your slack app

Open the tab/link that you saved in step 0. On the left side of the page under the Features menu, click on OAuth & Permissions. Here you’ll be able to set the permissions for your bot. A good rule for which permissions to add is to check out these methods, decide which ones you want to use, and click on them to see which permissions they require. For now, let’s just add one:

Under Bot Token Scopes click Add an OAuth Scope and add chat:write. This will allow your bot to send messages. Click on Install to Workspace close to the top of this page, then click Allow to install the app.

Step 7: Save your tokens and signing secrets

On the left side of the browser under the Settings section click on Basic Information scroll down until you see Signing Secret click on Show to show the secret, then copy it to your clipboard.

Go to your project folder and open the .env file. In that file add:

SIGNING_SECRET=paste-your-signing-secret-here

Click on OAuth & Permissions again and copy the Bot User Auth Token. Save it in your .env file as

BOT_TOKEN=paste-your-OAuth-Bot-Token-Here

Step 8: Connect your express App to your Slack App

Add the following code under the //YOUR CODE HERE section of app.js:

const token = process.env.BOT_TOKEN
const eventsApi = require('@slack/events-api')
const slackEvents = eventsApi.createEventAdapter(process.env.SIGNING_SECRET)
const { WebClient, LogLevel } = require("@slack/web-api");
const client = new WebClient(token, {
logLevel: LogLevel.DEBUG
});
app.use('/', slackEvents.expressMiddleware())slackEvents.on("message", async(event) => {
console.log(event)
})

There are a couple of things going on here. This code:

const eventsApi = require('@slack/events-api')
const slackEvents = eventsApi.createEventAdapter(process.env.SIGNING_SECRET)
***app.use('/', slackEvents.expressMiddleware())slackEvents.on("message", async(event) => {
console.log(event)
})

Allows our app to receive messages that occur on channels that it has been added to. At the moment, the app will simply console.log anything that comes in.

This part:

const { WebClient, LogLevel } = require("@slack/web-api");
const client = new WebClient(token, {
logLevel: LogLevel.DEBUG
});

Will allow our app to respond to some (or all) of those messages.

Let’s startup our app! Go to your app.js and run npm run dev. Also, let’s start up an ngrok server in another terminal window by running ngrok http 3000 from the terminal. You should see a response that looks like this:

Session Status                online
Session Expires 1 hour, 59 minutes
Version 2.3.40
Region United States (us)
Web Interface http://127.0.0.1:404
Forwarding http://feaf909adcfc.ngrok.io -> http://localhost:3
Forwarding https://feaf909adcfc.ngrok.io -> http://localhost:

Copy the https link (before the ->).

Now let’s go back to the slack api website, and click on Event Subscriptions under the Features section. Flip the switch to turn on event subscriptions, and an input field labeled Request URL should pop up. Paste the ngrok server url into that field. You should see a Verified checkmark next to the field. Scroll down to Subscribe to bot events, then click on Add Bot User Event, and then add message.channels. Now, click Save Changes. A yellow banner should pop up instructing you to reinstall your app to your workspace. Reinstall it, and you should be ready to receive messages.

Finally go to a slack channel (ideally one that you created for testing) and add the bot to that channel. You can do this by clicking on the dropdown next to the channel’s name, then click on Integrations then click Add Apps and find your app. In the terminal where your node.js app is running, you should see something like this:

{
type: 'message',
subtype: 'channel_join',
ts: '***',
user: '***',
text: '<@***> has joined the channel',
inviter: '***',
channel: '***',
event_ts: '***',
channel_type: 'channel'
}

You should also see a new console.log every time someone sends a message in that channel.

Step 9: Make your bot reply!

Go to your app.js file and change this code:

slackEvents.on("message", async(event) => {
console.log(event)
})

To this:

slackEvents.on("message", async(event) => {
if(!event.subtype && !event.bot_id)
client.chat.postMessage({
token,
channel: event.channel,
thread_ts: event.ts,
text: "Hello World!"
})
}
})

The if(!event.subtype && !event.bot_id) ensures that the bot won’t respond to things like people joining a channel and that it won’t reply to its own (or other bots) messages. These docs describe how to use the chat.postMessage api method. I’ve chosen to reply in thread by passing in the event’s ts number. If you don’t include a thread_ts attribute the response will simply be posted to the channel itself (not the thread). Send a message in your slack channel, and you should see something like this:

Step 10: Make it do cool things!

At this point you can do a variety of things with this app. Explore the methods listed here to get a feel for the possibilities. In part 2 (coming on 7/14) we’ll discuss how to connect a database to this app.

--

--