# Slack Destination Config Reference


> Complete Rudder CLI reference for the Slack destination config keys, channel routing, message templates, and source types.



[Slack](https://www.rudderstack.com/docs/destinations/streaming-destinations/slack/) is a business messaging destination. RudderStack turns `identify` and `track` events into messages and posts them to Slack channels through incoming webhooks, from its servers.

In a Slack destination spec:

- `type: slack`
- `definition_version: 1`

## Sample configuration

```yaml
version: rudder/v1
kind: destination
metadata:
  name: slack-prod
spec:
  id: slack-prod
  display_name: Slack Production
  type: slack
  definition_version: 1
  enabled: true
  config:
    webhook_url: "{{ .SLACK_WEBHOOK_URL }}"

    incoming_webhooks_type: modern
    event_channel_settings:
      - name: Order Completed
        webhook: "{{ .SLACK_ORDERS_WEBHOOK_URL }}"
        regex: false
      - name: "^Trial (Started|Ended)$"
        webhook: "{{ .SLACK_GROWTH_WEBHOOK_URL }}"
        regex: true

    identify_template: "Identified {{name}}{{newline}}Plan: {{plan}}"
    event_template_settings:
      - name: Order Completed
        template: "{{name}} completed an order worth {{revenue}}"
        regex: false

    whitelisted_trait_settings:
      - email
      - plan
    deny_list_of_events:
      - Heartbeat

    connection_mode:
      web: cloud
      cloud: cloud
    consent_management:
      web:
        - provider: oneTrust
          consents:
            - analytics
```

The above example sets `incoming_webhooks_type` to `modern`, so each channel entry carries its own `webhook` instead of a `channel` name — see [Channel routing](#channel-routing). The webhook URLs are secrets, written as `{{ .VAR }}` references — see [Secrets](#secrets).

## Config keys

`config` accepts only the keys listed below. The [shared config key rules](https://www.rudderstack.com/docs/rudder-cli/destination-types/#config-key-rules) cover unknown keys, defaults, and immutability.

**Info:** Slack accepts only `identify` and `track` events. RudderStack doesn&#39;t deliver any other event type to it.

### Connection

<div class="rs-ckeys">
<div class="rs-ckey" id="webhook_url">
  <div class="rs-ckey__title">
    <p class="rs-ckey__name">webhook_url</p>RequiredSecret</div>
  <p class="rs-ckey__field">
    Type:
    <code>string</code>
  </p>
<p class="rs-ckey__field">
  Description:
  Slack incoming webhook URL. RudderStack posts every <code>identify</code> message here, and every <code>track</code> message that <a href="#channel-routing" >channel routing</a> doesn&rsquo;t send elsewhere.
</p>

<div class="rs-ckey__notes">
  <p class="rs-ckey__field">Notes:</p>
  <ul>
<li>At most 100 characters, and must not contain line breaks.</li>
<li>Any value containing <code>.ngrok.io</code> is rejected.</li>
<li>Templates aren&rsquo;t accepted in place of a literal; a template is measured as text against the same limits.</li>
</ul>

</div>

<div class="rs-ckey__extra">
  <p>Supply it as a <code>{{ .VAR }}</code> reference rather than a literal — see <a href="#secrets" >Secrets</a>.</p>
<p>See <a href="https://www.rudderstack.com/docs/destinations/streaming-destinations/slack/#how-do-i-obtain-the-incoming-webhook-url" >How do I obtain the incoming webhook URL?</a>.</p>

</div>

</div>

</div>

### Channel routing

`event_channel_settings` sends `track` events to channels other than the one `webhook_url` posts to, and `incoming_webhooks_type` decides how. `identify` messages always go to `webhook_url`.

<div class="rs-ckeys">
<div class="rs-ckey" id="incoming_webhooks_type">
  <div class="rs-ckey__title">
    <p class="rs-ckey__name">incoming_webhooks_type</p></div>
  <p class="rs-ckey__field">
    Type:
    <code>string</code>
  </p><p class="rs-ckey__field">
    Default value:
    <code>legacy</code>
  </p>
<p class="rs-ckey__field">
  Description:
  How a matching <code>event_channel_settings</code> entry reaches its channel.
</p>

<div class="rs-ckey__notes">
  <p class="rs-ckey__field">Notes:</p>
  <ul>
<li><code>legacy</code> — RudderStack posts through <code>webhook_url</code> and names the entry&rsquo;s <code>channel</code> in the message. The dashboard marks this method as due for deprecation.</li>
<li><code>modern</code> — RudderStack posts to the entry&rsquo;s own <code>webhook</code>, a URL from a Slack app with incoming webhooks enabled for that channel.</li>
</ul>

</div>

<div class="rs-ckey__extra">
  See <a href="https://www.rudderstack.com/docs/destinations/streaming-destinations/slack/#event-channel-settings" >Event channel settings</a>.
</div>

</div>

<div class="rs-ckey" id="event_channel_settings">
  <div class="rs-ckey__title">
    <p class="rs-ckey__name">event_channel_settings</p></div>
  <p class="rs-ckey__field">
    Type:
    <code>array of objects</code>
  </p>
<p class="rs-ckey__field">
  Description:
  Routes <code>track</code> events to channels by event name. RudderStack uses the first entry that matches, and posts an event that matches none through <code>webhook_url</code>.
</p>

<div class="rs-ckey__notes">
  <p class="rs-ckey__field">Notes:</p>
  <ul>
<li><code>name</code> — event name to match. At most 100 characters, and must not contain line breaks. It also must not contain a parenthesized group that holds <code>*</code>, <code>+</code>, <code>{</code>, or <code>|</code> and is followed by <code>*</code>, <code>+</code>, <code>?</code>, or <code>{</code> — such as <code>(a|b)+</code> — even when <code>regex</code> is <code>false</code>.</li>
<li><code>regex</code> — boolean. <code>true</code> treats <code>name</code> as a regular expression, which matches anywhere in the event name — anchor it with <code>^</code> and <code>$</code> to match the whole name. Omit it, or set <code>false</code>, for an exact match.</li>
<li><code>channel</code> — channel to post to when <code>incoming_webhooks_type</code> is <code>legacy</code>: a channel name such as <code>#orders</code>, or <code>@user</code> for a direct message. At most 100 characters, and must not contain line breaks. Quote it, since an unquoted <code>#</code> starts a YAML comment.</li>
<li><code>webhook</code> — incoming webhook URL to post to when <code>incoming_webhooks_type</code> is <code>modern</code>. Same limits as <code>webhook_url</code>, including the <code>.ngrok.io</code> ban. <strong>Secret</strong> — see <a href="#secrets" >Secrets</a>.</li>
<li>Templates aren&rsquo;t accepted in place of a literal in these fields; a template is measured as text against the same limits.</li>
<li>Rudder CLI doesn&rsquo;t check that an entry carries the field its webhook type uses. RudderStack skips an entry without it, as though its <code>name</code> never matched.</li>
</ul>

</div>

<div class="rs-ckey__extra">
  <div class="rs-code">
  <div class="rs-code__head">yaml<button class="rs-code__copy" type="button">
      
      Copy
    </button>
  </div>
  <div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">incoming_webhooks_type: legacy
event_channel_settings:
  - name: Order Completed
    channel: &#34;#orders&#34;
  - name: &#34;^Trial (Started|Ended)$&#34;
    channel: &#34;#growth&#34;
    regex: true</code></pre></div>
</div><p>See <a href="https://www.rudderstack.com/docs/destinations/streaming-destinations/slack/#event-channel-settings" >Event channel settings</a>.</p>
</div>

</div>

</div>

### Message templates

Both template keys take [Handlebars expressions](https://www.rudderstack.com/docs/destinations/streaming-destinations/slack/#handlebar-expressions). Write each template in quotes: an unquoted value starting with `{` isn't read as a string in YAML. Rudder CLI substitutes only `{{ .VAR }}` references, which start with a dot, so `{{name}}` reaches Slack as written.

A template can use:

| Expression | Value |
| :-----| :-----|
| `{{name}}` | The user's name — `traits.name`, or first and last name — falling back to their username or email, then to `User <userId>`, or `Anonymous user <anonymousId>`. |
| `{{event}}` | The event name. `track` only. |
| `{{property_name}}`, `{{properties.property_name}}` | An event property, where `property_name` is its name — such as `{{revenue}}`. `track` only. |
| `{{trait_name}}` | A trait, where `trait_name` is its name — such as `{{plan}}`. `identify` only. `{{traitsList.trait_name}}` works in both. |
| `{{traits}}` | The user's traits as `key: value` text, limited to `whitelisted_trait_settings` when it's set. |
| `{{propertiesList}}` | Every event property as `key: value` text. `track` only. |
| `{{newline}}` | A line break. Templates can't contain literal line breaks, so this is the only way to write a multi-line message. |

<div class="rs-ckeys">
<div class="rs-ckey" id="identify_template">
  <div class="rs-ckey__title">
    <p class="rs-ckey__name">identify_template</p></div>
  <p class="rs-ckey__field">
    Type:
    <code>string</code>
  </p>
<p class="rs-ckey__field">
  Description:
  Template for the message an <code>identify</code> event posts. When omitted, RudderStack posts <code>Identified {{name}}</code> followed by the user&rsquo;s traits as <code>key: value</code> pairs, limited to <code>whitelisted_trait_settings</code> when it&rsquo;s set.
</p>

<div class="rs-ckey__notes">
  <p class="rs-ckey__field">Notes:</p>
  <ul>
<li>At most 1000 characters, and must not contain line breaks.</li>
<li><code>{{ path || fallback }}</code> templates aren&rsquo;t accepted in place of a literal; the value is measured as text against the same limits.</li>
</ul>

</div>

<div class="rs-ckey__extra">
  <div class="rs-code">
  <div class="rs-code__head">yaml<button class="rs-code__copy" type="button">
      
      Copy
    </button>
  </div>
  <div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">identify_template: &#34;Identified {{name}}{{newline}}Plan: {{plan}}&#34;</code></pre></div>
</div><p>See <a href="https://www.rudderstack.com/docs/destinations/streaming-destinations/slack/#identify-template-settings" >Identify template settings</a>.</p>
</div>

</div>

<div class="rs-ckey" id="event_template_settings">
  <div class="rs-ckey__title">
    <p class="rs-ckey__name">event_template_settings</p></div>
  <p class="rs-ckey__field">
    Type:
    <code>array of objects</code>
  </p>
<p class="rs-ckey__field">
  Description:
  Templates for the messages <code>track</code> events post, by event name. RudderStack uses the first entry that matches. An event that matches none posts <code>{{name}} did {{event}}</code>.
</p>

<div class="rs-ckey__notes">
  <p class="rs-ckey__field">Notes:</p>
  <ul>
<li><code>name</code>, <code>regex</code> — match events on the same terms as <a href="#event_channel_settings" ><code>event_channel_settings</code></a>.</li>
<li><code>template</code> — the message template. At most 1000 characters, and must not contain line breaks.</li>
<li><code>{{ path || fallback }}</code> templates aren&rsquo;t accepted in place of a literal in these fields; the value is measured as text against the same limits.</li>
</ul>

</div>

<div class="rs-ckey__extra">
  <div class="rs-code">
  <div class="rs-code__head">yaml<button class="rs-code__copy" type="button">
      
      Copy
    </button>
  </div>
  <div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">event_template_settings:
  - name: Order Completed
    template: &#34;{{name}} completed an order worth {{revenue}}&#34;</code></pre></div>
</div><p>See <a href="https://www.rudderstack.com/docs/destinations/streaming-destinations/slack/#event-template-settings" >Event template settings</a>.</p>
</div>

</div>

</div>

### Filtering

<div class="rs-ckeys">
<div class="rs-ckey" id="whitelisted_trait_settings">
  <div class="rs-ckey__title">
    <p class="rs-ckey__name">whitelisted_trait_settings</p></div>
  <p class="rs-ckey__field">
    Type:
    <code>array of strings</code>
  </p>
<p class="rs-ckey__field">
  Description:
  Traits RudderStack lists in the default <code>identify</code> message and in <code>{{traits}}</code>. When empty, every trait is listed. A template can still name any trait directly.
</p>

<div class="rs-ckey__notes">
  <p class="rs-ckey__field">Notes:</p>
  <ul>
<li>Each trait name is at most 100 characters, and must not contain line breaks.</li>
<li>Templates aren&rsquo;t accepted in place of a literal; a template is measured as text against the same limits.</li>
</ul>

</div>

<div class="rs-ckey__extra">
  <div class="rs-code">
  <div class="rs-code__head">yaml<button class="rs-code__copy" type="button">
      
      Copy
    </button>
  </div>
  <div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">whitelisted_trait_settings:
  - email
  - plan</code></pre></div>
</div>
</div>

</div>

<div class="rs-ckey" id="deny_list_of_events">
  <div class="rs-ckey__title">
    <p class="rs-ckey__name">deny_list_of_events</p></div>
  <p class="rs-ckey__field">
    Type:
    <code>array of strings</code>
  </p>
<p class="rs-ckey__field">
  Description:
  <code>track</code> event names RudderStack doesn&rsquo;t post to Slack. A match is exact and case-sensitive, and RudderStack fails a matching event with a configuration error instead of posting it.
</p>

<div class="rs-ckey__notes">
  <p class="rs-ckey__field">Notes:</p>
  <ul>
<li>Each name is at most 100 characters, and must not contain line breaks.</li>
<li>Templates aren&rsquo;t accepted in place of a literal; a template is measured as text against the same limits.</li>
</ul>

</div>

</div>

</div>

### Per-source keys

Both keys are objects keyed by the local source type — the tokens listed under [Source types](#source-types). A key naming a source type this destination doesn't support fails validation.

<div class="rs-ckeys">
<div class="rs-ckey" id="connection_mode">
  <div class="rs-ckey__title">
    <p class="rs-ckey__name">connection_mode</p></div>
  <p class="rs-ckey__field">
    Type:
    <code>object</code>
  </p>
<p class="rs-ckey__field">
  Description:
  Maps each source type you connect to the mode its events reach Slack in, using the modes in <a href="#source-types" >Source types</a>.
</p>

<div class="rs-ckey__notes">
  <p class="rs-ckey__field">Notes:</p>
  <ul>
<li>An entry is required for each source type you connect — see <a href="#connect-a-source" >Connect a source</a>.</li>
</ul>

</div>

<div class="rs-ckey__extra">
  <div class="rs-code">
  <div class="rs-code__head">yaml<button class="rs-code__copy" type="button">
      
      Copy
    </button>
  </div>
  <div class="highlight"><pre class="chroma"><code class="language-yaml" data-lang="yaml">connection_mode:
  web: cloud
  cloud: cloud</code></pre></div>
</div>
</div>

</div>

<div class="rs-ckey" id="consent_management">
  <div class="rs-ckey__title">
    <p class="rs-ckey__name">consent_management</p></div>
  <p class="rs-ckey__field">
    Type:
    <code>object</code>
  </p>
<p class="rs-ckey__field">
  Description:
  Consent provider configuration per source type. The entry shape, accepted providers, and the rules on <code>resolution_strategy</code> and <code>consents</code> are shared across all destination types — see <a href="https://www.rudderstack.com/docs/rudder-cli/destination-types/#consent-management" >Consent management</a>.
</p>

</div>

</div>

## Source types

Slack accepts events from these source types in the mentioned connection modes:

| Source type | Connection mode |
| :-----| :-----|
| `android` | `cloud` |
| `android_kotlin` | `cloud` |
| `ios` | `cloud` |
| `ios_swift` | `cloud` |
| `web` | `cloud` |
| `unity` | `cloud` |
| `react_native` | `cloud` |
| `flutter` | `cloud` |
| `cordova` | `cloud` |
| `cloud` | `cloud` |
| `warehouse` | `cloud` |

Every source type is `cloud` only — RudderStack posts to Slack from its servers, never in device mode.

`warehouse` is the token a [Reverse ETL source](https://www.rudderstack.com/docs/sources/reverse-etl/) resolves to. Rudder CLI manages the destination’s `warehouse` entry — if the destination is connected to a Reverse ETL source, set `connection_mode.warehouse: cloud` in its spec, or `apply` removes it.

Rudder CLI can also declare the Reverse ETL connection itself, for the types listed under [Supported destinations](https://www.rudderstack.com/docs/rudder-cli/yaml-retl-connections/#supported-destinations) — see [Manage Reverse ETL Connections using Rudder CLI](https://www.rudderstack.com/docs/rudder-cli/retl-connections/).

**Info:** The dashboard additionally offers Slack to AMP and Shopify sources. Rudder CLI doesn&#39;t manage those connections, so `amp` and `shopify` are invalid here.

## Connect a source

An event stream connection to this destination is checked against two rules at `validate` time.

**The source's type must be supported.** A source's type resolves to one of the tokens above before the check — a JavaScript source resolves to `web`, and webhook and server-side SDK sources resolve to `cloud`. Every type an event stream source can resolve to is supported here, so this check always passes.

**The destination config must carry a `connection_mode` entry for that source type.** This lives on the destination spec, not on the [connection spec](https://www.rudderstack.com/docs/rudder-cli/yaml-connections/). Without it:

```text
destination 'slack-prod' config has no 'connection_mode' entry for source type 'web'
```

Slack needs no additional config keys to connect a source of any type.

## Secrets

`webhook_url` and each `event_channel_settings` entry's `webhook` are the secret keys. Write each one you use as a `{{ .VAR }}` reference and supply the value at apply time:

```yaml
config:
  webhook_url: "{{ .SLACK_WEBHOOK_URL }}"
  event_channel_settings:
    - name: Order Completed
      webhook: "{{ .SLACK_ORDERS_WEBHOOK_URL }}"
```

```bash
export RUDDER_SLACK_WEBHOOK_URL="..."
export RUDDER_SLACK_ORDERS_WEBHOOK_URL="..."
rudder-cli apply

# or
rudder-cli apply --var-file secrets.vars.yaml
```

Note that:

- `rudder-cli import` writes only the secrets the API returns, as `{{ .VAR }}` references, and leaves the others out. Add any secret key it leaves out, then supply the variables before you apply — see [Secrets](https://www.rudderstack.com/docs/rudder-cli/destination-types/#secrets).
- Each substituted value is validated like a literal, so a webhook URL still has to meet the `webhook_url` limits.

See [How to Use Variable Substitution in Rudder CLI](https://www.rudderstack.com/docs/rudder-cli/variable-substitution/).

## Changes by release

<p>No changes since this type became available.</p>

For changes across every destination type, see [Destination Type Changes by Release](https://www.rudderstack.com/docs/rudder-cli/destination-types/changes/).

## See more

- [Slack Destination](https://www.rudderstack.com/docs/destinations/streaming-destinations/slack/) for incoming webhook setup, Handlebars expressions, and message examples
- [Destination Type Reference for Rudder CLI](https://www.rudderstack.com/docs/rudder-cli/destination-types/) for the rules shared across destination types
- [Destination YAML Reference](https://www.rudderstack.com/docs/rudder-cli/yaml-destinations/) for the spec envelope

