Create a Slack Bot with Node.js: The Definitive Guide
Tags: javascript, node, tutorial, slackbot
Published: 2021-10-09 06:10:17

If this is the millionth article you've found on how to build a Slack bot with Node.js, I'm sorry. 

I've built a few Slack bots, some of which have launched on the Slack App Directory. I'm going to give you a no-bullshit tutorial on creating a Slack bot with Node.js.

We'll build an internal tool that your team can use to get information about your customers using a slash command. I'm not going to teach you how to build a Slack app for the Slack App Directory.

> Quick plug: if you want to skip this entire article and focus on writing your internal tool, try [Runtime](Runtime).

## Set up Ngrok

[Ngrok](https://ngrok.com/) is how you'll connect your Slack workspace (on the internet) to your locally-running Slack bot (on your machine). It has a free plan, but the Basic plan is affordable and extremely useful for building Slack bots.

> **Security note**: Ngrok exposes your machine to the internet, making it a potential attack vector. If you're building your Slack bot on your work machine, get Ngrok approved by your security team.

Create an Ngrok account and follow the set-up steps. When you're finished, expose a web server on port 8080:

```bash
ngrok http 8080
```

This should produce the Ngrok console UI:

```
ngrok by @inconshreveable

Tunnel Status                 online
Version                       2.0/2.0
Web Interface                 http://127.0.0.1:4040
Forwarding                    http://92832de0.ngrok.io -> localhost:8080
Forwarding                    https://92832de0.ngrok.io -> localhost:8080

Connnections                  ttl     opn     rt1     rt5     p50     p90
                              0       0       0.00    0.00    0.00    0.00
```

> If you're on the free Ngrok plan, **don't close this terminal window**. The forwarding URL is randomly generated, and will change when you restart Ngrok.

Take note of the `Forwarding` URL. In the example above, it is: `https://92832de0.ngrok.io`.

## Set up your Slack app

Before we start writing code, we need to create a Slack App.

1. Navigate to [https://api.slack.com/apps?new_app=1](https://api.slack.com/apps?new_app=1).
2. Select **From an app manifest**.
3. Replace `<NGROK_FORWARDING_URL>` with your Ngrok forwarding URL in the App Manifest YAML file below.

> In the Ngrok example above, we would use `https://92832de0.ngrok.io`. So, the `redirect_urls` example below would become: `https://92832de0.ngrok.io/slack/oauth_redirect`

4.  Copy-paste the YAML contents in the **Enter app manifest below** section.
```yaml
_metadata:
  major_version: 1
  minor_version: 1
display_information:
  name: NodeBot
  description: Our internal Slack bot.
features:
  bot_user:
    display_name: NodeBot
    always_online: true
  slash_commands:
    - command: /customer
      url: <NGROK_FORWARDING_URL>/slack/events
      description: Get data about a customer
      usage_hint: /customer <customer id>
      should_escape: false
oauth_config:
  redirect_urls:
    - <NGROK_FORWARDING_URL>/slack/oauth_redirect
  scopes:
    bot:
      - commands
      - chat:write
      - chat:write.public
settings:
  org_deploy_enabled: false
  socket_mode_enabled: false
  token_rotation_enabled: false
```

App Manifest for your Slack bot
4. Select **Next**, then select **Create**.

Scroll down to the **App credentials **section and take note of the following values:

- `Client ID`
- `Client secret`
- `Signing secret`

Finally, install the app to your Slack workspace.

1. Select **Install App** on the left sidebar.
2. Select **Install to Workspace**, and select **Allow** on the installation page.
3. Take note of the `Bot User OAuth Token`.

## Set up your Slack bot code

Let's ensure your local environment is set up correctly. The dependencies for this Slack bot are as follows:

- `node >=12.13.0`
- `npm >=6.12.0`

Start by creating a new directory for the Slack bot and initialising `npm`:

```bash
mkdir slackbot-node
cd slackbot-node
npm init
```

Follow the prompts (tip: hold down the Enter key).

Let's install the project dependencies. Our main dependency is [Bolt](https://github.com/slackapi/bolt-js), the official Slack framework for building Slack apps with JavaScript.

    npm install --save @slack/bolt dotenv
    npm install --save-dev nodemon

### Add your environment variables

1. Create a `.env` file.
2. Add the following contents to your `.env` file, and add the values you took note of in the **Set up your Slack app** section.

```
SLACK_CLIENT_ID=<YOUR SLACK CLIENT ID>
SLACK_CLIENT_SECRET=<YOUR SLACK CLIENT SECRET>
SLACK_SIGNING_SECRET=<YOUR SLACK SIGNING SECRET>
SLACK_BOT_USER_TOKEN=<YOUR SLACKBOT USER TOKEN>
SLACK_OAUTH_STATE_SECRET='my-state-secret'
```

### Create the bot server

1. Create an `index.js` file. This will be the entry point for our bot server.
2. Copy-paste the following code:
```js
require("dotenv").config();
const { App } = require("@slack/bolt");

const port = process.env.PORT || 8080;

const app = new App({
  token: process.env.SLACK_BOT_USER_TOKEN,
  signingSecret: process.env.SLACK_SIGNING_SECRET,
});

// Slash command handler goes here.

(async () => {
  await app.start(port);

  console.log(`🤖 Slack bot at your service (http://localhost:${port})`);
})();
```

3.  Check the server works by starting the bot server with `nodemon`.

> `nodemon` restarts the server whenever we edit our `index.js` file

```bash
nodemon --exec node index.js
```

You should get the following output:
```
[nodemon] 2.0.13
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node index.js`
🤖 Slack bot at your service (http://localhost:8080)
```

## Add a slash command

The **App Manifest** file that we used to create our Slack app has already added a slash command for us; it's called `/customer`. Whenever somebody in your Slack workspace types `/customer`, Slack will send a POST request to your bot server; we need to program our bot server to respond correctly to the `/customer` slash command.

Add the following code to `index.js`:

```
// Handle the /customer slash command
app.command('/customer', async ({ command, ack, respond }) => {
  // Acknowledge command request
  await ack();

  await respond('Slack bot at your service!');
});
```

Now, we can test the slash command in Slack. Type `/customer` in Slack. This should yield the following result:
![Slash command example](https://blog.runtimehq.com/content/images/2021/10/Screen-Shot-2021-10-09-at-3.21.55-pm.png)

### Getting customer data

Finally, the juicy part. The method for getting customer data will vary based on your tech stack and where your customer data lives. Typically, you'll execute a database query here. For now, let's return some dummy user data.

> Format your response with the [Slack Block Kit Builder](https://app.slack.com/block-kit-builder/T019RHBDBKP#%7B%22blocks%22:%5B%7B%22type%22:%22section%22,%22text%22:%7B%22type%22:%22mrkdwn%22,%22text%22:%22*Jane%20Doe*%20(jane@company.com)%5Cn%3E-%20Enterprise%20plan%5Cn%3E-%2010%20active%20users%5Cn%3E-%20$1002%20total%20spend%22%7D%7D%5D%7D).
```js
const customerData = {
  name: "Jane Doe",
  email: "jane@company.com",
  activeUsers: 10,
  plan: "Enterprise",
  totalSpend: "$1002.26",
};

// Format the text however you like; Slack supports Markdown.
const header = `*${customerData.name}* (${customerData.email})`;
const body = `>${customerData.plan} plan\n>${customerData.activeUsers} users\n>${customerData.totalSpend} total spend`;

const response = {
  response_type: "in_channel", // make the response public
  blocks: [
    {
      type: "section",
      text: {
        type: "mrkdwn",
        text: `${header}\n${body}`,
      },
    },
  ],
};

await respond(response);
```

Let's run it in Slack and see the result. Type `/customer` in Slack:
![Final slash command example](https://blog.runtimehq.com/content/images/2021/10/Screen-Shot-2021-10-09-at-3.21.38-pm.png)

---

Building and maintaining internal Slack bots is a hassle. I built [Runtime](https://runtimehq.com) to help you rapidly create custom Slack bots. Write your internal script in your technology of choice, and Runtime handles the rest. Let me know what you think on [Twitter](https://twitter.com/tom__quirk).