Skip to main content
Watch live demos of top features from Winter ’25 here.

Build a Bolt App

Learning Objectives 

After completing this unit, you’ll be able to:

  • Enable your Bolt app to access Slack.
  • Explain listener functions.
  • Add event listeners to your app.
  • Add interactivity to your app.

Remix the Bolt for JavaScript App Template in Glitch

With the app configured and installed, it’s time to set up a new Bolt app with your app’s credentials.

To make development simple, this module uses Glitch, a tool that simplifies building and hosting apps. While a free Glitch account is great for development, your server won’t stay running while your app is idle. This means you need to keep Glitch open in your browser while you develop and test your app.

When your app is production-ready, you may want to host it elsewhere or upgrade your Glitch account.

Note

If you prefer running your app locally, you can use a tool like ngrok. There’s an example of using ngrok in the documentation’s Getting Started guide.

  1. Open your Glitch environment.
  2. Click this link to remix (or clone) the Bolt starter project.
  3. Once the remix is complete, the project shows up in your project list. In the example, it’s named actually-triangular-pigeon.Project list on Glitch, with actually-triangular-pigeon highlighted by a red box
  4. Click your project to load it.
  5. Then click app.js.

In the app.js file, you can see the @slack/bolt package imported and instantiated. Under that, the app’s server is set up and run so that it can receive incoming events from Slack.

You add more later. First, add the credentials from your Slack app configuration. Remember to keep Glitch open throughout this process. 

Head back to your app page on the Slack api site.

Add App Credentials

Retrieve your Signing Secret and Bot User OAuth Access Token. 

  1. Head to your Slack app configuration page on the Slack API site.
  2. Click Basic Information from the sidebar.
  3. Scroll down to the App Credentials section.
  4. Copy your Signing Secret and save it for the next step in your text editor.
  5. Click OAuth & Permissions from the sidebar.
  6. Click Copy to copy your Bot User OAuth Access Token and save it for the next step.

With your secret and token saved, head back over to Glitch.

  1. In your Glitch project, navigate to the .env file located on the left sidebar.
  2. Paste your Bot User OAuth Access Token in the Variable Value field directly after SLACK_BOT_TOKEN (1).
  3. Paste your Signing Secret in the Variable Value field directly after SLACK_SIGNING_SECRET (2). The app uses the signing secret to verify that incoming requests are coming from Slack. Bolt handles the verification automatically when the Signing Secret is passed into the App constructor..env file with the Variable Value field after SLACK_BOT_TOKEN marked with a 1, and the Variable Value field after SLACK_SIGNING_SECRET marked with a 2

If you click Logs at the bottom of the Glitch file navigator, you should see that your Bolt app is running!

Logs open with the message Bolt app is running!

Get to Know Listener Functions

Slack apps typically receive and respond to one to many requests from Slack. For each type of incoming request from Slack, there is a corresponding listener function to handle and respond. 

Here is a subset of the listeners Bolt apps can pass a function to.

Listener

Description

app.event(eventType, fn)

Listens for Events API events. The eventType is a string used to identify the specific event.

app.message([pattern ,], fn)

Convenience listener to handle events of type message. The pattern can be any substring or RegExp expression.

app.action(actionId, fn)

Listens for interactive events from a Block element such as a user interaction with a button. The actionId identifier is a string that matches a block element’s action_id.

app.shortcut(callbackId, fn)

Listens for global and message shortcut invocations. The callbackId is a string or RegExp pattern that matches a shortcut’s callback_id, which is specified in the app configuration.

The full list can be found in the Bolt reference documentation. It’s time to configure your app to listen and respond to events, interactions, and interactivities! 

Subscribe to Events

To listen to Events API events, your app needs to enable event subscriptions.

  1. Head over to your Slack app page on the Slack API site if you’re not there already.
  2. Click Event Subscriptions in the sidebar.
  3. Event Subscriptions should activate automatically. You can also toggle it on if needed.
  4. You’re presented with an input box to enter a Request URL. A Request URL is where HTTP requests are sent for events in which your app is subscribed. If you created your app from the template, your request URL is currently https://project-name.glitch.me/slack/events.
  5. Instead of project-name, add your own Glitch project’s name.
    1. Click Settings then Go to project page. The Live site URL contains your project name, everything after https:// and before .glitch.me.Share your project popup with the Glitch project name highlighted by a red box, actually-triangular-pigeon
  1. Head back to the Events Subscriptions page on the Slack API site and enter the request URL. It should look like this, https://actually-triangular-pigeon.glitch.me/slack/events
    Bolt for JavaScript listens for all incoming requests at the /slack/events route by default, which is why it’s appended to the Request URL.
  2. Click Save Changes to save your work.
  3. Then, click Subscribe to bot events to open the section. Here you see message.channels under Event Name. This event listens for all messages posted to public channels your app is in. With the request URL enabled, your app should begin receiving these events.

Add an Events Listener

Event subscriptions use the event() listener, which you can find examples of in the Bolt documentation. For now, you use the message() listener to listen and respond to messages.

  1. Head over to your Glitch project.
  2. Add the following to your app.js file just under // Space for your code



app.message('hello', async ({ message, say }) => {

    await say(`Hey there <@${message.user}>`);

});

Glitch auto saves your work.

app.js file with code inputted just under // Space for your code highlighted by a red box

Behind the scenes, the message() listener is the same as using app.event(“message”, fn) besides the additional say() parameter passed to the listener function. The say() parameter exposes the event’s response URL which, unlike calling chat.postMessage(), doesn’t require additional scopes to reply to message events.

As long as Glitch is up and running in a separate tab, your app should automatically restart. You can now send a message that contains “hello” inside of the channel your app is added to. The app should respond.

Slack channel with FS3 post hello and sample_app response Hey there @FS3

This basic example gives you a place to start customizing your app based on your use case. Let’s try something a little more interactive by sending a button element rather than plain text.

Set Up Interactivity

To use features like buttons, select menus, datepickers, modals, and shortcuts, you need to enable interactivity. Similar to event subscriptions, you need to specify a request URL for Slack to send the action request (such as a user clicked your button).

  1. Back on your Slack app configuration page, click Interactivity & Shortcuts in the sidebar.
  2. Toggle Interactivity to On. You see that there’s another Request URL box.
  3. By default, Bolt is configured to use the same endpoint for interactive components that it uses for events, so use the same request URL as above.
  4. Click Save Changes in the lower right-hand corner of the page, and that’s it! Your app is set up to handle interactivity.

Add an Action Listener to Respond to Message

When listening for interactivity, you use the action() listener. Before setting up the action() listener you modify the message() listener to send a button element.

  1. Head over to your Glitch project.
  2. In app.js, replace the previous code snippet to include a new section.
// Message listener function called for messages containing "hello"

app.message('hello', async ({ message, say }) => {

    await say({

        "blocks": [

            {

                "type": "section",

                "text": {

                    "type": "mrkdwn",

                    "text": `👋 Hey there <@${message.user}>`

                },

                "accessory": {

                    "type": "button",

                    "text": {

                        "type": "plain_text",

                        "text": "Click Me",

                        "emoji": true

                    },

                    "action_id": "click_me_button"

                }

            }

        ]

    });

});

previous code replaced by code from above, highlighted by a red box

The value of say() is now an object containing an array of blocks. Blocks are components of a Slack message, and can range from text to images to datepickers. In this case, it contains a section block that includes a button as an accessory.

Note

To design messages and other Block Kit surfaces, you can use Block Kit Builder. It has a set of built-in templates for common use cases, and a convenient drag-and-drop interface with the corresponding JSON payload on the right.

Block Kit can’t populate notifications or search by default, so the text field should be used to make your messages more accessible. To learn more about the text field there is information on the chat.postMessage reference page.

In the button accessory object, there is an action_id. This acts as a unique identifier that you can pass to your listener function to only listen to interactive events corresponding to that block element.

Your app should be restarted, then you can send another message containing hello that your app will reply to with a message containing the button element. But if you click the button, nothing happens (yet!).

In channel, FS3 post hello with sample_app response with a wave emoji and Hey there @FS3

Add an Action Listener to Respond to a Button Interaction

Let’s add an action() listener function to respond to the button click with a follow-up message.

  1. Head back to your Glitch project.
  2. Add the following action listener in app.js
// Action listener function called when an interactive component with action_id of “click_me_button” is triggered

app.action('click_me_button', async ({ ack, body, client, say }) => {

    // Acknowledge action request before anything else

    await ack();

    let channelID = body.channel.id

    let userID = body.user.id

    // Respond to action with an ephemeral message

    await client.chat.postEphemeral({

    channel: channelID,

    user: userID,

    text: `<@${userID}> clicked the button! 🎉 `

  });

});

Notice ack() being called inside of the listener function. ack() is used to acknowledge that your app received the event from Slack. After your app is restarted, you can click the button again and your app will respond with the new message.

In channel, FS3 post hello with sample_app response with a wave emoji and Hey there @FS3, then a response after the button click, @FS3 clicked the button! With a party popper emoji

Note

If you’re having troubles running the app, take a look at the finished code in actions.js within your project’s examples folder. 

Where Do We Go from Here?

You now have your first Bolt for JavaScript app that uses Bolt core concepts to listen and respond to different events coming from Slack! 

With the basics, you can start exploring more Bolt and platform features. Here are a few paths you may consider trekking.

  • Go through the examples folder within your Glitch project. There are a few files with different code samples you can copy-and-paste in your project.
  • Read the Bolt for JavaScript documentation to learn about advanced functionality and find code snippets showcasing the possible.
  • Level-up your app’s design using Block Kit Builder.

Explore other surfaces where your app has access to, like the home tab and popup modals.

Share your Trailhead feedback over on Salesforce Help.

We'd love to hear about your experience with Trailhead - you can now access the new feedback form anytime from the Salesforce Help site.

Learn More Continue to Share Feedback