Skip to main content

Formatting message text

These are developer-focused instructions for posting messages to Slack using API methods.

For user instructions on message formatting in your Slack client, refer to this Help Center article.

You can format messages within the various surfaces of your app, such as messages, modals, or the app's App Home. The Block Kit blocks and elements that comprise the layouts for these surfaces frequently use text objects to insert content, which can be formatted with markdown to create useful visual highlights or utilize certain syntax to trigger special parsing.

Block Kit Builder is a visual prototyping sandbox that will allow you to choose from, configure, and preview all the available blocks. You can also check out the reference guide on blocks, which contains the specifications of every block and the JSON fields required for each.

Formatting with markdown

There are a variety of ways to format message using markdown in Slack:

  • You can use it in most Block Kit text objects by setting the type field to mrkdwn. (There are a few blocks and elements that only allow plain_text; these are called out in the documentation on blocks).
  • We support markdown types for rich text when using Block Kit. Check out our rich text block and markdown block references for more details.
  • The mrkdwn argument is the default formatting method when publishing a message, for example by using the chat.postMessage API method.
  • The mrkdwn property can also be used to format blocks and elements used when unfurling links in messages using composer unfurls or within Work Objects.
  • The markdown_text argument can be used to format text when beginning a new streaming conversation, for example by using the chat.startStream API method.
Markdown vs. mrkdown

Note that mrkdwn is Slack's custom text formatting syntax. It is inspired by markdown, but uses different rules. Read on for more details.

Basic visual styles

Apply visual styles as follows:

  • _italic_ will produce italicized text
  • *bold* will produce bold text
  • ~strike~ will produce strikethrough text

Line breaks

You can use multi-line text in app-generated text. Insert a newline by including the string \n in your text. For example, the following formatting:

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

will produce the following text:

This is a line of text.
And this is another one.

Block quotes

You can highlight text as a block quote by using the > character at the beginning of one or more lines:

This is unquoted text\n>This is quoted text\n>This is still quoted text\nThis is unquoted text again

Code blocks

If you have text that you want highlighted like code (like this), surround it with backtick (`) characters:

This is a sentence with some `inline *code*` in it.

Text within inline code blocks will not use any other formatting, so it can be useful even if you're not displaying actual code.

You can also highlight larger, multi-line code blocks by placing 3 backticks before and after the block:

```This is a code block\nAnd it's multi-line```

Lists

There's no specific list syntax in app-published text, but you can mimic list formatting with regular text and line breaks as follows:

- Mihara and New Tideland\n- RaviHyral\n- TranRollinHyfa

Links

To link to URLs in a conversation, include the URL directly in mrkdwn text and it will be auto-transformed by the server into a link.

URLs with spaces will break, so we recommend that you remove any spaces from your URL links.
This message contains a URL: https://docs.slack.dev/
So does this one: https://docs.slack.dev/

You can also use mrkdwn to manually add links:

This message contains a URL: <https://docs.slack.dev/>

Adjust the text that appears as the link from the URL to something else:

<https://docs.slack.dev/|This message is a link>

And create email links:

<mailto:perihelion@univmiharanewtideland.com|Email Perihelion>

You can also use Block Kit buttons as links by using the url parameter in button elements.

When you use any of the messaging API methods to retrieve a message, you'll see that auto-transformed URLs are shown in the formatted mrkdwn text. So this:

This message contains a URL: https://docs.slack.dev/

Will be represented in the API as:

This message contains a URL <https://docs.slack.dev/>

While this message:

So does this one: https://docs.slack.dev/

Will be retrieved in this form:

So does this one: <https://docs.slack.dev/|https://docs.slack.dev/>

Emoji

Emoji can be included directly in text. Once published, Slack will convert the emoji into their common 'colon' format. For example, a message published as follows:

It's Friday 🎉

will be converted into 'colon' format:

It's Friday :tada:

If you're publishing text with emoji, you don't need to worry about converting them. If you're retrieving messages, you'll receive the emojis in 'colon' format, so you may want to convert them back to their unicode emoji form. The list of supported emoji are taken from https://github.com/iamcal/emoji-data.

Escaping text

It's important to know that there are some characters in text strings that must be escaped.

Slack uses &, <, and > as control characters for special parsing in text objects, so they must be converted to HTML entities if they're not going to be used for their parsing purpose. Therefore, if you want to use one of these characters in a text string, you should replace the character with its corresponding HTML entity as shown:

SymbolHTML entity
&&amp;
<&lt;
>&gt;

You shouldn't encode the entire piece of text, as only the specific characters shown above will be decoded for display in Slack.

Advanced formatting

We mentioned earlier the need to escape certain strings in text objects. These strings are used to trigger special parsing of the text, such as user mentions or advanced date formatting. Read on to learn more about this advanced formatting.

Linking to channels

Text can refer to a Slack channel and transform that reference into a link to the channel itself. This uses a similar mrkdwn syntax as regular URL links:

Why not join <#C123ABC456>?

In this example, #C123ABC456 is the channel's ID. Your app can get this ID from an interaction request payload, the Event API payload sent when one of the event types occurs, or by looking it up directly with the conversation-related methods of the Web API. You can also manually retrieve a specific channel's ID from its URL:

https://app.slack.com/client/E123ABC456/C123ABC456

When text containing the channel linking syntax is published in an app surface, the ID is automatically converted to show the actual name of the conversation. If any of the channel members do not have access to the linked private channel, they will only see an unclickable private channel label.

If you're retrieving messages, use the conversations.info API method to look up by channel ID and find out other relevant information, such as the actual name of the channel.

Mentioning users

A mention is a special type of reference that provides a link to the mentioned user's profile in the text. If the mention is included in an app-published message, the mentioned user will also be notified about the reference. This Help Center article describes what that notification process looks like.

To mention a user, provide their user ID with the following syntax:

Hey <@U012AB3CD>, thanks for submitting your report.

Your app can get this user ID from an interaction request payload, the Event API payload sent when one of the event types occurs, or by looking them up via the users.list Web API using another unique piece of information you have about them, such as their email address. You can also manually retrieve a specific user's ID by clicking the overflow button in their Slack profile and choosing the Copy member ID option. When text containing the user-mention syntax is published by an app, the ID will be automatically converted to show the display name of the user.

If you're retrieving messages, you can use the users.info API method to look up by user ID and find out other relevant information, such as their display name.

Mentioning groups

As with users, you can also mention user groups, which will link to the group's profile.

If the mention is included in an app-published message, Slack will notify each user in the group about the mention. To mention a user group, provide the group ID with the following general syntax:

`<!subteam^ID>`

!subteam^ is a literal string that should not change, but ID should be replaced with the actual user group ID. Here's an example:

Hey <!subteam^SAZ94GDB8>, there's a new task in your queue.

Your app can get this group ID from the Event API payload sent when one of the subteam event types occurs, or by looking them up via the usergroups.list API method. You can also manually retrieve a specific user group's ID from the URL shown when viewing its profile. When text containing the user group mention syntax is published by an app, the ID will be automatically converted to show the name of the user group.

If you're retrieving messages, you can use the usergroups.list API method to look up by user group ID and find out other relevant information.

Special mentions

These special groups should be mentioned sparingly, as they tend to notify a large group of users.

Use discretion by mentioning individuals or more specific groups whenever possible.

There are a few core user groups built into Slack that can be mentioned:

  • @here notifies the active members of a channel.
  • @channel notifies all members of a channel, active or not.
  • @everyone notifies every person in the #general channel (i.e., every non-guest member of a workspace).

To add these to a message, use the following syntax:

Hey <!here>, there's a new task in your queue.

Date formatting

Text containing a date or time should display that date in the local timezone of the person seeing the text. For app-published text, there is a handy date syntax available to format a Unix timestamp, and Slack will handle the timezone localization for you.

The displayed time will be based on the timezone setting of the device used to observe the text, not the timezone set within Preferences in the Slack client being used to observe it. For more details about managing your timezone preferences, refer to this Help Center article.

The <!date> command will format the timestamp using tokens within a string that you set, and it must include some fallback text for older Slack clients. Here's the general syntax to use:

<!date^timestamp^token_string^optional_link|fallback_text>

This can be broken down as follows:

  • The wrapping <> is used as a control character for the whole string, and ^ is used to divide different parts of the string.
  • !date indicates to use the special date parsing.
  • timestamp is a number in standard Unix time format, the date and time that you want to include in your text.
  • token_string should provide a formatting for your timestamp, using plain text along with any of the following tokens:
    • {date_num} is displayed as 2014-02-18. It will include leading zeros before the month and date and is probably best for more technical integrations that require a developer-friendly date format.
    • {date} is displayed as February 18th, 2014. The year will be omitted if the date is less than six months in the past or future.
    • {date_short} is displayed as Feb 18, 2014. The year will be omitted if the date is less than six months in the past or future.
    • {date_long} is displayed as Tuesday, February 18th, 2014. The year will be omitted if the date is less than six months in the past or future.
    • {date_pretty} displays the same as {date} but uses "yesterday", "today", or "tomorrow" where appropriate.
    • {date_short_pretty} displays the same as {date_short} but uses "yesterday", "today", or "tomorrow" where appropriate.
    • {date_long_pretty} displays the same as {date_long} but uses "yesterday", "today", or "tomorrow" where appropriate.
    • {time} is displayed as 6:39 AM or 6:39 PM in 12-hour format. If the client is set to show 24-hour format, it is displayed as 06:39 or 18:39.
    • {time_secs} is displayed as 6:39:45 AM 6:39:42 PM in 12-hour format. In 24-hour format it is displayed as 06:39:45 or 18:39:42.
    • {ago} is displayed as a human-readable period of time, e.g. 3 minutes ago, 4 hours ago, 2 days ago.
  • optional_link can be provided if your timestamp needs to be linked, specified using a standard, fully qualified URL.
  • fallback_text should be included just in case the client is unable to process the date. Consider adding timezone information to your fallback text since it will potentially be different from the timezone of the person reading it.

Here are some examples of date formatting strings:

<!date^1392734382^Posted {date_num} {time_secs}|Posted 2014-02-18 6:39:42 AM PST>

<!date^1392734382^{date} at {time}|February 18th, 2014 at 6:39 AM PST>

<!date^1392734382^{date_short}^https://example.com/|Feb 18, 2014 PST>

If you're retrieving messages, you'll receive the <!date> string back in its original format, and you can use the information above to parse it if necessary.

Automatic parsing

Earlier, we explained how to include various types of special syntax in your app-published text. What we didn't mention is that you can just include the same text that a user would post directly in Slack to achieve some of these things. For example, given the following text:

<http://example.com|example link> http://example.com #general @here 🤩 :smile:

Most of these references can be automatically parsed upon publishing to turn them into links or mentions:

<http://example.com|example link> <http://example.com> <#C0838UC2D|general> <!here> :star-struck: :smile:

You can achieve this in different ways, depending on where the text is being placed:

Disabling automatic parsing

If you want to disable automatic parsing, you have a couple options depending on the type of text:

  • For text in layout blocks set a verbatim attribute of your text objects to true.
  • For the top-level text field, or text in secondary message attachments, as long as you exclude the link_names argument when publishing, this will be disabled by default. Regular URLs will still be converted into clickable links; however, to disable this, you can pass the parse argument with a value of none when publishing.

Why you should consider disabling automatic parsing

Even with this functionality available, we still recommend that you use the manual methods shown above. This is important because the names of conversations or user groups may change at any time. What was previously a functioning reference may no longer work. Meanwhile, an ID will always remain the same. The same holds true for special mentions, such as @here.

Another good reason to disable automatic parsing is to be more explicit about where you want to include links and mentions. This could prevent random text from being unintentionally parsed and turned into a link. For example, imagine your app passes user input from a third-party service straight into the published text. Using automatic parsing, if this user text contained a string like @everyone, your app could unintentionally send a notification to the entire workspace.

We've since deprecated this functionality for user mentions, so always parsing manually will keep you prepared in case automatic parsing is deprecated for other entities in the future, such as conversations or user groups.

Creating rich message layouts

We can take message formatting a step further by making rich message layouts using Block Kit, which enables us to structure complex data in a readable and understandable way within messages.

While message text formatting can improve information density and visual hierarchy at a basic level, you can combine that with Block Kit layout blocks and block elements to vastly expand the possibilities for visual organization.

You can create messages using blocks and introduce the tools for building a compelling visual experience. Stack individual blocks together into an array that defines the visual layout and style of your messages. Check out the formatting with rich text tutorial for more details.

Defining a single block

Each block is represented in our APIs as a JSON object. Here's an example of a section block:

{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "New Paid Time Off request from <example.com|Fred Enriquez>\n\n<https://example.com|View request>"
}
}

Every block contains a type field, specifying which of the available blocks to use, along with other fields that describe the content of the block.

Stacking multiple blocks

Individual blocks can be stacked together to create complex visual layouts. When you've chosen each of the blocks you want in your layout, place each of them in an array, in visual order, as follows:

[
{
"type": "header",
"text": {
"type": "plain_text",
"text": "New request"
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Type:*\nPaid Time Off"
},
{
"type": "mrkdwn",
"text": "*Created by:*\n<example.com|Fred Enriquez>"
}
]
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*When:*\nAug 10 - Aug 13"
}
]
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "<https://example.com|View request>"
}
}
]

Block Kit Builder allows you to drag, drop, and rearrange blocks to design and preview Block Kit layouts. Alternatively, you can use the reference guide on blocks to manually generate a complete blocks array, like the one shown above.

Adding your blocks array

Blocks are added to messages by adding a blocks array to the message payload as follows:

{
"channel": "C123ABC456",
"text": "New Paid Time Off request from Fred Enriquez",
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "New request"
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Type:*\nPaid Time Off"
},
{
"type": "mrkdwn",
"text": "*Created by:*\n<example.com|Fred Enriquez>"
}
]
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*When:*\nAug 10 - Aug 13"
}
]
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "<https://example.com|View request>"
}
}
]
}

When you're using blocks in your message payload, the top-level text field becomes a fallback message displayed in notifications. Blocks should define everything else about the desired visible message.

Sending messages with blocks

There are multiple ways for apps to send messages, and you can use Block Kit with most of them. Here's a list of the methods you can use to publish messages with blocks:

There are no special OAuth scopes needed to publish blocks beyond those already specified within the methods above.

Read our guide to sending messages for more details. Once you've decided which sending method to use, consult that method's reference guide to find out where to include your JSON payload. When you call your selected method, your stack of blocks will transform into a beautiful new message, like this:

Message with blocks showing a review of a hotel with 1 stars given

Notes on retrieving formatted messages

If you're retrieving messages, we've included some extra details in the sections above to help you parse the formatting syntax. This will allow you to properly format it for display on different services, or help your app fully understand the intent of a message. Here are the general steps involved in detecting advanced formatting syntax:

  1. Detect all sub-strings matching <(.*?)>.
  2. Within those sub-strings, format content starting with #C as a channel link.
  3. Format content starting with @U or @W as a user mention.
  4. Format content starting with !subteam as a user group mention.
  5. Format content starting with ! according to the rules for special mentions.
  6. For any other content within those sub-strings, format as a URL link.

Disabling formatting

If you want to turn Slack's markdown-like processing off, you have different options depending on where the text is:

Legacy: secondary attachments

This feature is a legacy part of messaging functionality for Slack apps. You can read more about them here.

Next steps

Congratulations! You've learned all about the message composition options available to Slack apps.

To learn about all the available blocks, head to the reference guide for blocks.

To learn about Block Kit elements, head to the reference guide for block elements.

To learn about formatting and unfurling links in messages, check out unfurling links in messages.