---
title: Slack notifications with Knock
description: Learn how to use Knock to send Slack notifications to your users.
section: Integrations > Slack
layout: integrations
---

This page covers how to use Knock to send notifications to Slack. Depending on your use case, there are a few different ways to approach this integration. This documentation serves as a starting point and will cover the basics of setting up a Slack integration with Knock regardless of your use case.

## What can I do with Knock's Slack integration?

Knock's Slack integration enables you to send notifications to [Slack channels](https://docs.knock.app/integrations/chat/slack/sending-a-message-to-channels) and [direct messages](https://docs.knock.app/integrations/chat/slack/sending-a-direct-message) to users via an authenticated Slack app, or via [webhooks for internal workspaces](https://docs.knock.app/integrations/chat/slack/sending-an-internal-message). You can create rich message templates using [markdown](#markdown-templates) or [Slack's block kit framework](#block-based-templates), and build integrations where customers connect your Slack app to their Slack workspaces.

This integration does not support Slack modals, slash commands, shortcuts, or interactive dialogs.

## How to connect Slack to Knock

Knock supports multiples ways to create a Slack integration depending on your technical requirements:

- Using Knock's managed approach with our [SlackKit components](/in-app-ui/react/slack-kit)
- Using Knock's [Slack-related React hooks](https://docs.knock.app/in-app-ui/react/slack-kit#using-slackkit-headless) with your own components
- Building the UI and OAuth flow entirely yourself

Regardless of your approach, you'll need a Slack app to send notifications from Knock to a Slack workspace. If you haven’t built a Slack app yet, you can get started in <a href="https://api.slack.com/start/quickstart#creating" target="_blank">Slack’s app documentation</a>.

Once you create your Slack app, you’ll be routed to its app management page within the Slack dashboard. It looks like this.

<Image
  src="/images/slack-app-management-page.png"
  width={3248}
  height={1942}
  alt="Slack app management page"
  border={false}
/>

If you are new to Slack apps, there are a few key concepts to understand:

- A <a href="https://api.slack.com/scopes" target="_blank">scope</a> is a permission granted to your Slack app when it joins a Slack workspace. You configure which scopes your app asks for in the **OAuth & Permissions** sidebar of your <a href="https://api.slack.com/apps" target="_blank">app management page</a>.
- Your Slack app is installed to a customer's workspace through the <a href="https://api.slack.com/authentication/oauth-v2" target="_blank">Slack OAuth flow</a>. In this flow, your app requests scopes and the user installing the app confirms which scopes to grant. You’ll need to surface this OAuth flow to your users wherever you want them to install your Slack app. Knock's [`SlackAuthButton` component](/in-app-ui/react/slack-kit#slackauthbutton--container) can help you with this.
- A Slack app can have bot token scopes and user token scopes. For almost all use cases, you’ll be using bot token scopes (<a href="https://api.slack.com/authentication/basics" target="_blank">this Slack doc explains why</a>). When you add bot token scopes to an app, you will **also** need to make sure your app has its display information configured. You can do this under the **App Home** sidebar on the <a href="https://api.slack.com/apps" target="_blank">app management page</a>.

In this section we'll complete the steps for setting up your Knock account and Slack app.

<Steps titleSize="h3">
  <Step title="Set up Slack app">
    First, you'll need to create the bot that you'll use to post notifications.

    <Callout
      emoji="🤖"
      title="Prepare existing Slackbot"
      text={
        <>

          <br />
          If you already have a Slackbot you want to use, you'll just need to
          make sure it has its redirect URL set and that it's publicly distributed, which
          is described below.
        </>
      }
    />

    The following steps will be completed in the **OAuth & Permissions** sidebar of your Slack app's <a href="https://api.slack.com/apps" target="_blank">management page</a>:

    <AccordionGroup>
      <Accordion title="Add a scope">
        When using an `access_token` stored in Knock to power your Slack integration, that token will need to contain the correct scopes to use the Slack API. Although If you're using SlackKit, the components can help you manage your scopes, but you have to add one in your Slack application's settings to start with so that it exposes the form for you to add a redirect URL.

        Here is the list of scopes we recommend adding to your app and the reasons they're required:

        - `chat:write`: This scope allows your bot to send messages to channels that the bot has been explicitly invited to, including private channels. It doesn't grant the ability to send messages to public channels without an invite.
        - `chat:write.public`: This scope extends the bot's capabilities to send messages to public channels without needing a specific invitation to those channels. It's an addition to the chat:write scope, offering broader access for the bot to interact within the workspace.
        - `channels:read`: This scope allows your bot to list all channels in a workspace and view details about specific channels (like name, topic, purpose, members), but does not grant access to private channels.
        - `groups:read`: This scope allows your app to list all private channels that the bot or user is a member of and to view details about those channels.
        - `users:read`: This scope allows your app to view all people in a workspace and is required if you want to query a user's Slack ID by email. **This scope is required to use [Knock's email-based user ID resolution](/integrations/chat/slack/sending-a-direct-message#enabling-email-based-user-id-resolution).**
        - `users:read.email`: This scope allows your app to view the email addresses of people in a workspace and is required if you want to query a user's Slack ID by email. **This scope is required to use [Knock's email-based user ID resolution](/integrations/chat/slack/sending-a-direct-message#enabling-email-based-user-id-resolution).**

      </Accordion>
      <Accordion title="Add redirect URL">
        Under **OAuth & Permissions** in the **Features** sidebar, you need to add a redirect URL so that Slack knows where to redirect users after they complete the OAuth handshake.

        If you plan on using SlackKit, copy and paste this redirect URL:

        <CopyableText
          label="https://api.knock.app/providers/slack/authenticate"
          content="https://api.knock.app/providers/slack/authenticate"
        />

        If you're building your own OAuth flow, you'll need to use a URL in your frontend application. You can reference this documentation on <a href="https://knock.app/blog/how-to-authenticate-users-in-slack-using-oauth" target="_blank">building a Slack OAuth flow</a> from scratch.
      </Accordion>
      <Accordion title="Set up public distribution">
        Under **Manage Distribution**, click the "Distribute app" button which will show you a list of items to complete to activate public distribution. If you've built the app from scratch and completed the previous steps, you should see all of these complete except for "Remove hard coded information."

        Check the box and then click "Activate Public Distribution."
      </Accordion>
    </AccordionGroup>

  </Step>
  <Step title="Add Slack app to Knock Slack integration">
    Now that your Slack app is set up, you'll want to reference three attributes in the **Basic Information** section:

    1. App ID
    2. Client ID
    3. Client secret

    You need to add this data to a new or existing Slack integration in the Knock dashboard to link your app to Knock. From the dashboard, you can [create a Slack integration](/concepts/channels#managing-channels) by navigating to **Channels and sources** in your account settings.
    <Image
    src="/images/integrations/chat/slack/create-slack-channel.png"
    className="rounded-md mx-auto border border-gray-200"
    alt="A Slack message"
    width={2000}
    height={1186}
    />

    <br />

    Once the channel exists, you can click "Manage configuration" to access the "Provider settings" section. This is where you'll paste the three strings referenced above.

    <Image
    src="/images/integrations/chat/slack/edit-slack-channel-config.png"
    className="rounded-md mx-auto border border-gray-200"
    alt="A Slack message"
    width={2000}
    height={1208}
    />

    <br />

    Click "Update settings" to save.

  </Step>
  <Step title="Use Slack channel in a workflow">
    In order to test this flow, you'll want to set up a workflow with a Slack channel step. Later on we'll discuss how you can [design your notification templates for Slack](/integrations/chat/slack/overview#designing-notification-templates-for-slack), but for now you can just add the channel step to a workflow. To actually send a notification to Slack, you'll need to add channel data to a user or object in Knock. We'll cover that in the next section.
    <Image
  src="/images/integrations/chat/slack/workflow-with-slack-step.png"
  className="rounded-md mx-auto border border-gray-200"
  alt="workflow with a Slack step"
  width={2000}
  height={1450}
/>
  </Step>
</Steps>

## How to set channel data for a Slack integration in Knock

In Knock, the [`ChannelData`](/managing-recipients/setting-channel-data) concept provides you a way of storing recipient-specific connection data for a given integration. If you reference the [channel data requirements for Slack](/managing-recipients/setting-channel-data#chat-app-channels), you'll see that there are two different schemas for a `SlackConnection` stored on a [`User`](/concepts/users) or an [`Object`](/concepts/objects) in Knock.

Here's an example of setting channel data on an `Object` in Knock.

<MultiLangCodeBlock
  snippet="objects.setChannelData.slack"
  title="Store Slack connection on object"
/>

<br />

<Callout
  type="alert"
  title="Potential confusion alert."
  style={{ marginTop: "0" }}
  text={
    <>
      In the example above, the <code>KNOCK_SLACK_CHANNEL_ID</code> variable is
      the id of the Knock channel you've created to represent your Slack app
      within the Knock dashboard. You can find it by going to{" "}
      <span className="font-bold">Integrations</span> {">"}{" "}
      <span className="font-bold">Channels</span> in the Knock dashboard and
      then copying the ID of your Slack app channel.
    </>
  }
/>

### Recipient channel data requirements

Here's an overview of the data requirements for [setting recipient channel data](/send-notifications/setting-channel-data) for either an incoming webhook or an access token Slack connection. Both will need to live under the `connections` key.

| Property    | Type                | Description                       |
| ----------- | ------------------- | --------------------------------- |
| connections | `SlackConnection[]` | One or more connections to Slack. |

    A `SlackConnection` can have one of two schemas, depending on whether you're using standard Slack OAuth scopes or an incoming webhook.
    We cover Slack app scopes in detail in our [Slack scopes documentation](/integrations/chat/slack-diy/slack-apps-and-scopes).

<AccordionGroup>
  <Accordion title="SlackConnection with an access token" description="For self-serve customer integrations">
      If you're using standard Slack OAuth with access token scopes, your `SlackConnection` schema looks like this. You'll use
    either a `channel_id` or `user_id` depending on whether you're storing connection data to message a channel or user in Slack:

    | Property     | Type     | Description                                                                                                                                                                                                                            |
    | ------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | access_token | `string` | A bot access token. Not required when the access token is <a href="/integrations/chat/slack/overview#tenant-channel-data-requirements" style={{ color: "var(--tgph-accent-11)", textDecoration: "underline" }}>stored on a tenant</a>. |
    | channel_id   | `string` | A Slack channel ID.                                                                                                                                                                                                                    |
    | user_id      | `string` | A Slack user ID.                                                                                                                                                                                                                       |

    <br/>

    ```json title="Slack channel_data with an access token"
    {
      "connections": [
        {
          "access_token": "ACCESS_TOKEN",
          "channel_id": "CHANNEL_ID",
          "user_id": "USER_ID"
        }
      ]
    }
    ```

  </Accordion>
  <Accordion title="SlackConnection with an incoming webhook url" description="For internal or one-off integrations">
     If you're using a Slack app with the `incoming-webhook` scope your `SlackConnection` schema is quite simple:

    | Property             | Type     | Description                     |
    | -------------------- | -------- | ------------------------------- |
    | incoming_webhook.url | `string` | The Slack incoming webhook URL. |


    ```json title="Slack channel_data with an incoming webhook URL"
    {
      "connections": [
        {
          "incoming_webhook": { "url": "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX" }
        }
      ]
    }
    ```

  </Accordion>
</AccordionGroup>

### Tenant channel data requirements

When you [map a Slack workspace to a tenant](/integrations/chat/slack/sending-a-message-to-channels#key-concepts) in Knock (as our [SlackKit](/in-app-ui/react/slack-kit) components do), you'll store the access token for that workspace as `channel_data` on the tenant. Then, when you apply the `tenant` to your workflow triggers Knock will [combine that access token with the recipient's](/integrations/chat/slack/sending-a-message-to-channels#merging-channel-data) `channel_data` to send notifications to the correct Slack workspace and channel. For this implementation method, the `access_token` on the recipient's `SlackConnection[]` data above is not required.

Here's an overview of the data requirements for setting channel data when storing an access token on a tenant.

| Property           | Type     | Description                                                  |
| ------------------ | -------- | ------------------------------------------------------------ |
| token              | `object` | An object containing the `access_token` obtained from Slack. |
| token.access_token | `string` | The `access_token` obtained from Slack.                      |

<br />

```json title="Slack channel_data on a tenant"
{
  "token": { "access_token": "ACCESS_TOKEN" }
}
```

### Choosing where to store channel data: users vs. objects

Depending on the Slack integration you build into your product, you’ll store the connection data you receive from Slack as `channel_data` on either a `User` or an `Object` in Knock.

<AccordionGroup>
  <Accordion title="Users" description="For notifying users via direct message">
    If your integration involves a user opting in to receive DMs from your Slack bot, you’ll be storing the channel data [on that user](/api-reference/users/set_channel_data) in Knock. When you want to notify this user, you'll include them as a recipient in a Knock workflow trigger.

    For this integration, you'll store a user's Slack `user_id` in the `SlackConnection` object. You can [enable email-based user ID resolution](/integrations/chat/slack/sending-a-direct-message#enabling-email-based-user-id-resolution) if you'd like Knock to automatically resolve these IDs on your behalf.

    Alternatively, you can manually find the correct `user_id` by querying Slack's API:
    - by <a href="https://api.slack.com/methods/users.lookupByEmail" target="_blank">a given user's email address</a>
    - for <a href="https://api.slack.com/methods/users.list" target="_blank">a list of all of a workspace's users</a>

    You'll need to be sure that you request the appropriate [`scopes`](/integrations/chat/slack/overview#set-up-slack-app) for these methods during the auth process.

  </Accordion>
  <Accordion title="Objects" description="For notifying Slack channels about non-user resources">
    If your integration involves a customer connecting a _non-user resource_ in their product (such as a project or a page) to a Slack channel, you’ll want to store that channel data [on an object](/api-reference/objects/set_channel_data) in Knock, as it’s not specific to any single user.

    You can find the correct `channel_id` and display a list of channels for your user to select from by querying the Slack API:
    - for <a href="https://api.slack.com/methods/conversations.list" target="_blank">a list of all of a workspace's channels</a>

    The [`SlackChannelCombobox`](/in-app-ui/react/slack-kit#slackchannelcombobox) component of Knock's SlackKit can help you with this.

    You can learn more about the Knock object model and see an example how to use it to power Slack notifications in our [Objects documentation](/concepts/objects).

  </Accordion>
</AccordionGroup>
<br />

## Designing notification templates for Slack

When you add a new Slack channel step to a workflow in Knock, you'll need to configure a template for that step so Knock knows how to format the message to Slack.

### Markdown templates

Editing a markdown template for Slack is just like editing any other markdown-based template in Knock. You can use <a href="https://shopify.github.io/liquid/" target="_blank">Liquid</a> to inject variables and add control tags (e.g. if-then, for-loop) into your template.

<Callout
  title="Knock fun fact."
  text={
    <>
      Slack uses a markdown-variant syntax called{" "}
      <a
        href="https://api.slack.com/reference/surfaces/formatting#basics"
        target="_blank"
      >
        mrkdwn
      </a>
      , but Knock handles this for you automatically, so you can write your templates
      in good old <a
        href="https://daringfireball.net/projects/markdown/"
        target="_blank"
      >
        {" "}
        markdown
      </a>.
    </>
  }
/>

Here's an example Slack template written in Knock using markdown.

```markdown title="A markdown-based Slack template with for-loop iteration"
Hi **{{ recipient.name | split:" " | first }}**,

There are {{ total_activities }} comments left on {{ page_name }}.

{% for activity in activities %}

- From **{{activity.actor.name}}**: "{{activity.comment.body}}""
  {% endfor %}

[**View page**]({{vars.base_url}}/{{account_id}}/pages/{{ page_id }})
```

In the example above we're using <a href="https://shopify.github.io/liquid/tags/iteration/" target="_blank">Liquid's for-loop tag</a> to iterate over the activities array produced by a Knock batch function. You can learn more about Knock batch functions and the state they produce in our [batch function documentation](/send-notifications/designing-workflows/batch-function).

### Block-based templates

For more advanced layouts in your Slack messages, including images and buttons, you'll need to use Slack's <a href="https://api.slack.com/block-kit" target="_blank">block kit UI framework</a> to build your notification templates. The block kit framework is a set of different JSON objects you can use together and arrange to create Slack app and notification layouts.

#### Designing block kit templates

To start you'll want to design your block-based Slack message template. The best way to do this today is to use <a href="https://app.slack.com/block-kit-builder/" target="_blank">Slack's block kit builder</a>. It gives you a drag-and-drop interface for building out your Slack templates, and outputs the JSON you'll need to bring into your Knock template.

Once you've designed your Slack template, copy the JSON from the block kit builder and bring it into your Knock notification template. You'll use the "Switch to JSON editor" button at the bottom right of the Knock template editor page to switch to our JSON editor, and then paste in the JSON you copied from the block kit builder.

<Callout
  emoji="🛣"
  title="Knock roadmap alert."
  bgColor="accent"
  text={
    <>
      In the future you'll be able to use a visual, drag-and-drop editor within
      Knock to build these block-based Slack templates without having to leave
      the Knock product. <br />
      <br /> If you're interested in this functionality, please shoot us a note at{" "}
      <a href="mailto:support@knock.app">support@knock.app</a> or use the feedback
      button at the bottom of this page.
    </>
  }
/>

#### Knock's JSON template editor

You can use liquid in the Knock JSON template editor just as you would in the markdown editor. This is helpful for both injecting variables into the text of your Slack UI blocks, as well as for using liquid control tags to control when certain blocks should be displayed and for iterating through an array and mapping its items into a list of Slack blocks.

Here's an example of a block kit UI template with liquid syntax added to iterate through a list of items.

```json title="A block kit UI template in Knock with for-loop iteration"
{
	"blocks": [
		{
			"type": "header",
			"text": {
				"type": "plain_text",
				"text": "Users marked for onboarding",
				"emoji": true
			}
		},
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": "Hi John,\n\n The following users have been assigned to you for onboarding today:"
			}
		},
		{% for activity in activities %}
		{
			"type": "section",
			"text": {
				"type": "mrkdwn",
				"text": "*{{activity.assigned_user.name}}* \n {{activity.assigned_user.email}} \n _{{activity.assigned_user.title}}_"
			},
			"accessory": {
				"type": "image",
				"image_url": "{{activity.assigned_user.avatar_url}}",
				"alt_text": "avatar image"
			}
		},
		{
			"type": "divider"
		},
		{% endfor %}
		{
			"type": "actions",
			"elements": [
				{
					"type": "button",
					"text": {
						"type": "plain_text",
						"text": "View in dashboard",
						"emoji": true
					},
					"value": "{{dashboard_url}}"
				}
			]
		}
	]
}
```

In the template above, we're using the `activities` array produced by a [batch function](/send-notifications/designing-workflows/batch-function) to iterate over a number of items that we want to display in our Slack message. For each one of those items, we're producing a `section` that includes both `text` and `image` blocks which reference variables from the `activity` from our `activities` array.

Here's an example of a Slack message produced with this template. **Note:** this template was produced by three separate workflow trigger calls to the Knock API, all of which were batched into a single message automatically using our batch function.

<Image
  src="/images/integrations/chat/slack/slack-json-block-example.png"
  width={600}
  height={467}
  className="rounded-md mx-auto border border-gray-200"
  alt="An example Slack message built with block kit UI"
/>
