Sign in

Message Formatting

All text in Slack uses the same system of escaping: chat messages, direct messages, file comments, etc.

These formatting instructions pertain to content posted programmatically to Slack. For instructions on formatting messages within Slack itself, consult this help center article.

Messages can contain any displayable Unicode sequence of characters (all messages must use UTF-8 encoding), but need to be slightly escaped by clients.

Before sending messages to Slack, clients should make the following transforms:

How to escape characters

3 Characters you must encode as HTML entities

There are three characters you must convert to HTML entities and only three: &, <, and >.

Slack will take care of the rest.

  • Replace the ampersand, &, with &amp;
  • Replace the less-than sign, < with &lt;
  • Replace the greater-than sign, > with &gt;

That's it. Don't HTML entity-encode the entire message. Of course, when you send your message using URL-encoding, you'll still need to URL encode the ampersand.

Try it!

URL encoding and Unicode

When sending messages using URL or POST-based parameters, as you may with chat.postMessage and similar approaches, you'll need to "URL encode" the parameter value containing your message.

Unicode characters, like many emojis and accent characters, should be presented in URL-encoded hex. For example, 🌊 is F0 9F 8C 8A in hex and further URL-encoded as %F0%9F%8C%8A.

A user types    : Hello & <world> 🌊
Encoded message : Hello &amp; &lt;world&gt; 🌊

And would be sent URL-encoded as:


Control sequences

Slack uses &, <, and > as control characters so that messages may contain special escaped sequences.

Linking to channels and users

For example, to refer to a channel or user within a message, a client should send the following messages:

Why not join <#C024BE7LR|general>?

Hey <@U024BE7LH|bob>, did you see my file?

These escape sequences are then forwarded to all members of the channel as usual, and clients can format these links specially. The readable name can be included after the ID, by separating them with a pipe (|) character. Both of these formats are valid:


Linking to URLs

For regular URL links, clients should just include the URL in the message; It is not the responsibility of individual clients to detect URLs within typed messages. For example, the following messages can be sent to the server:

This message contains a URL

So does this one:

URL detection is performed by the server. We do this so that URL detection (a non-trivial operation) is performed consistently across multiple clients. The example messages will be broadcast to other clients as follows:

This message contains a URL <>

So does this one: <|>

In the first case, the URL is detected as-is. In the second, the full URL is included first, then a pipe character (|), then finally the originally typed version of the URL.

The server will also detect mailto links in the format <email|user>. For example:



Some messages contain special words with extra behavior. For these we use the format <!foo>, where foo is a special command. Currently defined commands are !channel, !group, !here, and !everyone (group is just a synonym for channel - both can be used in channels and groups). These indicate an @channel, @group, @here, or @everyone message, and should cause a notification to be displayed by the client.

Note that to display @here on older mobile clients you will need to specify a label with the <!here> command (eg. <!here|here>).

For paid teams there is an additional command for User Groups that follows the format <!subteam^ID|handle>. (subteam is literal text. ID and handle are replaced with the details of the group.) These indicate a User Group message, and should cause a notification to be displayed by the client. User Group IDs can be determined from the usergroups.list API endpoint. For example, if you have a User Group named happy-peeps with ID of S012345, then you would use the command <!subteam^S012345|happy-peeps> to mention that group in a message.

More commands will be added in the future. Unrecognized commands can be output as-is, with the enclosing brackets to indicate something about the text is special. If a label is present it should be used.

For example:

  • <!foo> should be displayed as <foo>
  • <!foo|label> should be displayed as <label>

Parsing modes

By default, messages you pass to API methods and webhooks will be assumed to be pre-formatted based on the above spec. That is, you can include marked up URLs, user links, channel links and commands, but we will still linkify any non-linked URLs present in your message.

IN  : Foo <!everyone> bar
OUT : Foo <!everyone> bar <>

By default, Slack will not linkify channel names (starting with a '#') and usernames (starting with an '@'). You can enable this behavior by passing link_names=1 as an argument. This behavior is always enabled in parse=full mode (see below).

IN  : Hello @bob, say hi to @everyone in #general
OUT : Hello <@U123|bob>, say hi to <!everyone> in <#C1234|general>

If you don't want Slack to perform any processing on your message, pass an argument of parse=none.

IN  : Foo <!everyone> bar
OUT : Foo <!everyone> bar

(In this case, Slack will still test the validity of your markup - we won't send invalid messages to clients).

If you want Slack to treat your message as completely unformatted, pass parse=full. This will ignore any markup formatting you added to your message.

IN  : Foo <!everyone> bar
OUT : Foo &lt;!everyone&gt; bar <>

In full parse mode, we will find and linkify URLs, channel names (starting with a '#') and usernames (starting with an '@').

Multiline Messages

You can post multiline messages through Slack's APIs. Insert a newline by including the characters \n in your text. For example:

    "text": "This is a line of text.\nAnd this is another one."

The above JSON payload will be displayed in the channel as:

Screenshot of a webhook with a newline

Try it!


Slack attempts to normalize emoji across multiple platforms using the following approach:

  1. All emoji sent to Slack (as chat message to the message server, or arguments to the API) are translated into the common 'colon' format (e.g. :smile:)
  2. At display time, Slack clients are encouraged to convert these colon-sequences into native Emoji where available, otherwise fallback to images.

The Slack message server and API handle conversion from several binary emoji formats - the Unicode Unified format (used by OSX 10.7+ and iOS 6+), the Softbank format (used by iOS 5) and the Google format (used by some Android devices). These Unicode code points will be converted into their colon-format equivalents.

The list of emoji supported are taken from

Formatting and Attachments

You can create richly-formatted messages using Attachments. Learn how to add attachments to messages.

Screenshot of attachments with colors

We recommend using a maximum of 20 attachments per message.

Message Formatting

Slack messages may be formatted using a simple markup language similar to Markdown. Supported formatting includes: ```pre```, `code`, _italic_, *bold*, and even ~strike~.; full details are available on our help site.

By default bot message text will be formatted, but attachments are not. To disable formatting on a non-user message, set the mrkdwn property to false. To enable formatting on attachment fields, set the mrkdwn_in array on each attachment to the list of fields to process. Some examples:

    "text": "*bold* `code` _italic_ ~strike~",
    "username": "markdownbot",
    "mrkdwn": true

Try it!

    "text": "*not bold*",
    "username": "markdownbot",
    "mrkdwn": false

Try it!

    "attachments": [
            "title": "Title",
            "pretext": "Pretext _supports_ mrkdwn",
            "text": "Testing *right now!*",
            "mrkdwn_in": ["text", "pretext"]

Try it!

Valid values for mrkdwn_in are: ["pretext", "text", "fields"]. Setting "fields" will enable markup formatting for the value of each field.

How to display formatted messages

If you want to display formatted messages on the web, your client should take the following steps:

  1. Detect all sequences matching <(.*?)>
  2. Within those sequences, format content starting with #C as a channel link
  3. Within those sequences, format content starting with @U as a user link
  4. Within those sequences, format content starting with ! according to the rules for the special command.
  5. For remaining sequences, format as a link
  6. Once the format has been determined, check for a pipe - if present, use the text following the pipe as the link label

Because the ampersands and angled brackets are already escaped, no further translation need take place (for a web-client). The server ensures that no extra un-escaped angled brackets or ampersands are included in the message.

When a client sends a message, the response that is returned by the server contains the server-formatted version of the message. Clients should use this to replace their own local version of the message so that urls are correctly highlighted.