Build Slack Home Tab in minutes using AWS Lambda and Amazon EventBridge

Reading Time: 9 minutes

When we built the first version of Vacation Tracker, UI for Slack integrations was very limited. You could make your integration interactive by mixing buttons and dropdowns. Luckily, a limited number of interactive elements combined with a grain of imagination lead to countless creative ideas. Not all of them provided the best user experience for our users, but they were way better than our biggest competitor – the big bad spreadsheet.

The first version of our product was similar to the following image. We improvised a calendar using simple buttons. No weekends? The limit was five buttons in a row. It’s a leave tracking app, who works during the weekends anyway? Many people, as we learned quickly.

Slack improved a lot in the last two years. They added a date picker, modals, input fields, and many other useful UI elements. Besides that, Slack improved their permission scopes, which was very important for Vacation Tracker, because we tried to know just a few most basic things about our users.

Our product was better than ever as one of our latest feedbacks says it’s super easy to use, much better than submitting paper forms. Managing your leave days is just one Slack command away.

However, not all of our users know how to use slash commands. Was it slash (“/”) vacation, hashtag vacation, or some other weird character?

Wouldn’t it be nice if we could have a place in Slack where users can find everything they need to know about Vacation Tracker? Something like a simple dashboard. Fortunately, someone at Slack thought the same.

Slack App Home tab

At the end of 2019, Slack introduced the Slack app toolkit. This toolkit is essential because it brought a better way to manage permissions, Block Kit, a new Slack UI framework, and — App Home tab!

An App Home is a private, one-to-one space shared by the user and the app. The user can reach the App Home from the conversation list within Slack or by clicking on the app’s name in messages.

An App Home is dynamic. We can use an App Home and Block Kit to show all critical information from Vacation Tracker to our users just in time. Even if our users do not know how to use slash commands, they’ll be able to request leaves directly from Slack by clicking the button in the Home tab.

It sounds like a significant improvement for our UX! Where do we start?

How does App Home tab work

To add an App Home page, you need to request necessary permissions and enable the home tab for your app, as explained in the Slack guide here.


You also need to create a Slack application and install it to your workspace, which is beyond the scope of this article, but many other guides cover it.


When your Slack integration is ready, you can show the UI on the home tab by sending an array of blocks to the views.publish Web API method. You can see more details about this API method and supported blocks by visiting an official Slack guide.

As the App Home tab is private and can be unique for each user, besides the blocks and the bot token, the views.publish Web API method requires an ID of the users that interacts with the Home tab. You can get IDs of all users from your database or from Slack’s Web API.

The other and probably better way to deal with the App Home tab is just in time. When a user opens an App Home tab, Slack sends the app_home_opened event. You can set up a webhook to receive the app_home_opened event, and publish or update an App Home tab for that specific user. This event contains a user ID, and you need to provide your new blocks and a valid bot token.

Making Slack integrations painless and scalable

We wrote about the way we use Amazon Web Services (AWS) and serverless architecture to build our product and Slack integration. You can read some of our articles about serverless and technology behind Vacation Tracker here and here on our blog, or in a few external sources, such as AWS blog, and other websites. In case you are not familiar with serverless, you can take a look at one of the linked articles for more info.

We use serverless and AWS to make our product and Slack integration scalable with a minimal amount of maintenance. Most of the time, Slack requires an answer from our system within three seconds, which is a long time if you do not have to parse an event, do a complex calculation, and also add a couple of hundred milliseconds of network latency and cold start. Fortunately, our cold start is less than 200ms because we use small Node.js modules. If you face a higher cold start latency, you might want to take a look at AWS Lambda Provisioned Concurrency.

Our initial architecture was similar to the following diagram. We connected all Slack webhooks to our API Gateway. The API Gateway then triggers different Lambda functions for different types of Slack integration (events, slash commands, or dialogs). Each of these functions parses the Slack messages, publish them to our Amazon Simple Notification Service (SNS) topic, and respond to Slack with 200 OK status. Then the SNS topic triggers other Lambda functions that do the business logic.

The architecture looks simple. However, the red square has nothing to do with our business logic and Vacation Tracker. These services would work the same for any Slack integration. Our philosophy is to try to outsource everything that is not part of our business logic. Unfortunately, there’s no simple service that would outsource this Slack integration in a way we need it, so we built one.

We already wrote about creating a serverless application that handles generic webhooks, and you can read about our journey and approach here. This solution does not work for Slack integration, because some of the webhooks need to answer verification request. Also, Slack sends some payloads as JSONs, some are URL encoded, but when you click on a button in Slack integration, Slack sends an URL encoded payload that contains stringified JSON. Our generic webhook handler is not able to unpack all of these specific payloads.

We decided to create another AWS Serverless Application Repository (SAR) application that handles Slack specific webhooks and provides an easy way for us to build new Slack integrations without thinking about parsing events and responding to Slack.


To learn more about SAR, read our previous article about the generic webhook handler here. To learn more about building and publishing serverless apps on SAR, see this excellent article.


As you can see in the following diagram, the architecture of our new integration looks similar to our initial architecture. However, there are two crucial differences: our SAR application hides webhook and event processing, and we replaced Amazon SNS with Amazon EventBridge. The EventBridge is a new service that brings a fully managed enterprise service bus to an AWS serverless offering. You can publish all the events there and then subscribe to your Lambda functions to one or multiple events containing a specific parameter. For example, you can trigger a specific function when the user opens a Slack Home Tab!

Let’s dive into the most exciting part of this article – the code.

Using our new serverless application

The easiest way to demonstrate the way our new SAR app works is to build something. So let’s build a simple todo list that looks similar to the following mockup.

To use our new serverless application, you need an active AWS account and basic knowledge of serverless and AWS Serverless Application Model (SAM). These prerequisites are beyond the scope of this article, but many online resources can teach you the basics of serverless and SAM. If you prefer books, you can check the excellent Running Serverless book, written by Gojko Adzic.

Once you setup all prerequisites, initialize a new SAM application with the node12.x runtime. And open your template.yaml file.


If you are using the new sam deploy --guided command, deploy the application once before modifying your template.yaml file. Then open the samconfig.toml file, and replace the following line:

capabilities = "CAPABILITY_IAM"

With the following configuration:

capabilities = "CAPABILITY_IAM CAPABILITY_AUTO_EXPAND"

This “CAPABILITY_AUTO_EXPAND” capability allows you to install SAR applications using SAM.


Modify your template.yaml file to look similar to the following code sample:

The previous code sample will setup the basics of your serverless application. This template does the following:

  • It tells Amazon CloudFormation, the beast behind AWS SAM, that you want SAM to take over.
  • It passes the two parameters to your SAM app:
    • EventBusName – tells SAM how to name your event bus, “SampleSlackEventBus” is a decent name.
    • BotToken – tells your app which bot token to use. In production, you probably want to get this from the API, but for a sample app you can pass a value from the “Install App” tab of your Slack App settings
  • It sets functions global configuration, so you don’t need to repeat that in each of your functions.
  • It defines resources, which we’ll do in a few minutes.
  • It defines an output, which is a webhook you can use for Slack integration.

Another warning for the new sam deploy --guided command users: Remember to add the “parameter_overrides” values to your samconfig.toml file. To do so, replace the existing “parameter_overrides” value with something similar to the following code sample:

parameter_overrides = "EventBusName=EVENT_BUS_NAME BotToken=xoxb-YOUR-BOT-TOKEN"

Replace the EVENT_BUS_NAME placeholder with your event bus name, and the xoxb-YOUR-BOT-TOKEN placeholder with a valid bot token for your Slack app.


The next step is the installation of our new SAR app. To do that, add the following code to the Resources section of your template.yaml file:

This code sample creates an EventBridge event bus and uses the value of the variable you provided as an event bus name. And it installs our SAR application. At the moment of writing, the current version of our app was 1.1.0, but you should use the latest version from SAR or our Github repository.

Now you have everything you need to start handling the events. The first event we want to handle is the opening of the App Home tab. Add the following Lambda function to the resources section of your template.yaml file.


Let’s go through this code sample line by line:

  • SlackHomeTab represents the name of your Lambda function. You can change this, but try to make it descriptive.
  • Type: AWS::Serverless::Function tells SAM that you want to add a Lambda function.
  • Properties define a list of properties for your function.
  • CodeUri: build/home-tab tells SAM to take the app code from the “home-tab” folder, located in the “build” folder. We use TypeScript for our Lambda functions if your source code is in some other location change this line.
  • Handler: lambda.handler tells SAM that we exported handler function from the lambda.js file. Change this value if your function or the file are named differrently.
  • The Environment section defines environment variables. We do not want to hardcode our bot token, so we pass it as the BOT_TOKEN environment variable in this section.
  • The Events section defines an event that triggers your Lambda function.

And now we came to the most exciting part of the code. See the following code example:

This pattern tells an EventBridge event bus to trigger this specific function if the event contains the following structure:

Our SAR application, in combination with the EventBridge, makes a powerful but easy-to-use library for Slack integrations. Besides specific events, you can target a specific slash command or even a click on the specific button in your Slack app.

To add another Lambda function that triggers on click on the “Add todo” button, you can add the following code snippet to the resources section of your template.yaml file:

As you can see, the only difference is the event pattern. Slack buttons send a payload that contains actions. If one of the actions has the “add_todo” value, EventBridge invokes this function.

Modal submission is just another event, and you can handle it by adding the following code to the resources section of your template.yaml file.

Now you need to write a code for your functions. If you want to see everything in action, feel free to use the code from our sample Github repository.

When you pull the code from our repository, run the npm install command to install the dependencies. Then run the npm run build command to build the TypeScript code. And finally, run the sam deploy command to deploy the application.

The deployment should output the webhook URL. Set this URL as a webhook URL in the “Event Subscriptions” and the “Interactive Components” sections in your Slack application settings.

The demo

The result should look similar to the following gif:

Not bad for a few minutes of coding!

Next steps and architecture evolution

This architecture gives you a simple but flexible and scalable architecture for your Slack integrations. By default, your integration can handle up to 1000 parallel requests. You can increase this number via AWS support. It gets even better; you are charged per usage. If no one uses your Slack integration, the infrastructure is free.

As a next step, you should add a database that would store bot tokens and other user preferences. We recommend using DynamoDB, AWS database that scales automatically and is an excellent fit for a serverless application.

You can also subscribe to our newsletter if you want to get articles similar to this one directly in your inbox.

Now, go and build something amazing! Keep an eye on the Vacation Tracker Home tab, which we’ll roll out to our users in the following few days.