Build a simple Slack app that sends one-way messages to a channel using a Node script.
Slack apps appear to be complex when getting started using their documentation. And many apps are complex. They are built to be distributed among multiple Slack teams, and they typically listen for input from users and adjust responses based on that input. They are apps, after all.
But they don't have to be. Sometimes you may just want to send a message to Slack based on some other event. You don't need to listen for input from users, but only want to send one-way messages.
This process is actually quite simple and only involves three basic steps:
Let's do it!
Let's create and configure a new Slack application.
Begin by going to api.slack.com/apps and clicking Create New App.
Choose From Scratch, then give it a name and choose the workspace where you want to install it.
In the basic information section, go into Incoming Webhooks.
Slide the toggle to enable the feature. After doing this, you will see a button near the bottom called Add New Webhook To Workspace. Click this and choose a channel where you'll install the app.
This doesn't mean it's the only channel the bot can post to. You can change this later, but have to pick something now.
After doing this, you'll see that the webhook integration has been added to the channel in your Slack team.
Navigate to OAuth & Permissions (under Features in the side navigation) and scroll down to the Scopes section.
Enable the following scopes as Bot Token Scopes:
chat:write
chat:write.public
incoming-webhook
(should already be enabled)If the channel you want to post to is a private channel, go back to Slack and invite the app user into the channel.
You will likely see a notification at this point, asking you to reinstall the application into the workspace after adding these scopes. Follow the steps it provides.
Finally, if you want to adjust how the app appears when posting messages, you can adjust the display information near the bottom of the Basic Information page under Settings.
Note that we'll have to come back here for some security credentials when we start writing code. But for now, let's move on to learn about blocks.
Slack messages are typically made up of blocks. These are structured JSON objects that tell Slack how to render the message. It gives you a lot of flexibility in how you present your message.
This is likely the thing you'll spend the most time adjusting so that your messages are formatted exactly as you'd like. Fortunately, there is a block kit builder that you can use to get more familiar with blocks.
Here's an example of blocks you might use to notify Slack that you just published a post.
{
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": ":fire: New post published to the site: <https://www.seancdavis.com/|*Working with Slack API*>"
}
},
{
"type": "divider"
},
{
"type": "context",
"elements": [
{
"type": "image",
"image_url": "https://avatars.githubusercontent.com/u/5245089?v=4",
"alt_text": "Sean C Davis"
},
{
"type": "mrkdwn",
"text": "Author: <https://www.seancdavis.com/|*Sean C Davis*>"
}
]
}
]
}
There are a few things that tripped me up as I was learning about blocks:
mrkdwn
(not markdown
).Here are the block kit docs, which are a nice reference while you're structuring your content.
The code is so surprisingly simple that I don't even need to show you an example project. It just takes a few steps.
If you don't have a project already, begin with a new blank Node.js project.
The only dependency we'll use here is Slacks's SDK, called @slack/bolt.
npm install @slack/bolt
If you also don't have a way to store and load environment variables, you can take advantage of dotenv.
npm install dotenv
We're going to retrieve and store three environment variables:
SLACK_SIGNING_SECRET
: Find this in the App Credentials section in the Basic Information page. Copy the Signing Secret.
SLACK_BOT_TOKEN
: This is under OAuth & Permissions. There should be a single token that you can copy. (See below for a screenshot.)
SLACK_CHANNEL
: The name of the channel that you are going to send the message to. I use an environment variable so that I can easily swap this out between development and production.
Once you have these values, paste them in the appropriate place in your project.
.env
SLACK_SIGNING_SECRET="..."
SLACK_BOT_TOKEN="..."
SLACK_CHANNEL="..."
Then we can write the script. And it's super simple!
index.mjs
import Slack from "@slack/bolt";
const app = new Slack.App({
signingSecret: process.env.SLACK_SIGNING_SECRET,
token: process.env.SLACK_BOT_TOKEN,
});
const blocks =
/* Add blocks payload here ... */
await app.client.chat.postMessage({
token: process.env.SLACK_BOT_TOKEN,
channel: process.env.SLACK_CHANNEL,
text: "...",
blocks,
});
Be sure to set the blocks
constant to the payload you've built with the block kit builder (or use my example).
And replace the text
property in postMessage
with an appropriate text representation of your message. This is for usages where Slack does not render block content.
Notice here that I'm using .mjs
as the file extension. This is so I could have access to top-level await
. You can also set "type": "module"
in your package.json
.
Now run the script and see the results!
I hope this serves as a solid foundation for you to build something great (or fun, or both)!
Feel free to create an issue if you have a question or trouble with this code.