Messaging & Formatting

Do threads and replies bridge between Slack and Microsoft Teams?

By SlackBridge Team · Last verified ·Applies to: Free, Pro

TL;DR. Yes. SlackBridge bridges threaded replies in both directions: a reply in a Slack thread arrives in Microsoft Teams as a reply on the corresponding Teams root message, and a reply on a Teams root message arrives in Slack inside the corresponding thread. Threading works by storing a Slack-timestamp to Teams-message-ID map when the parent is bridged. If the parent was never bridged, or was bridged more than seven days ago (the map that links the two messages is kept for seven days), the reply still arrives but as a new top-level message rather than inside the thread.

What's the short version?

Threaded replies bridge in both directions. A reply on a Slack message arrives in Microsoft Teams as a reply on the corresponding Teams message; a reply on a Teams message arrives in Slack inside the matching thread. The conversation reads in the same order on both sides.

Scenario What SlackBridge does
Reply on a bridged Slack message Looks up the Teams message ID stored when the parent was bridged; delivers the reply with that as the root
Reply on a bridged Microsoft Teams message Detects the parent ID from the Microsoft Graph change-notification payload; looks up the matching Slack thread_ts; delivers the Slack reply with that thread context
Reply where the parent was never bridged, or was bridged more than seven days ago (the map expires) Logs slack.thread.no_parent_mapping and delivers the reply as a new top-level message
Reply where the parent's destination message ID is missing (e.g., Bot Framework returned no ID at original send time) Delivers the reply as a new top-level message. SlackBridge does not guess which message was the parent.

Both Slack and Microsoft Teams use a flat thread model: there is a root message and a flat list of replies. Replies-to-replies do not exist as a separate visual structure on either platform, so the bridge does not have to do anything special to flatten depth.

If you only remember one thing: a reply threads correctly as long as its parent was bridged within the last seven days. Outside that, or if the parent was never bridged at all, the reply still arrives, as a new top-level message.


How does Slack-thread-to-Teams-thread bridging work?

When you reply to a message in a Slack channel, Slack delivers the message event with a thread_ts field that points to the parent message's timestamp. The bridge detects this and resolves the corresponding Microsoft Teams message ID:

1. Slack reply event arrives
2. Detect: thread_ts is set AND not equal to ts → this is a thread reply
3. Resolve parent Teams message ID:
   a. Look up the message mapping by parent's Slack timestamp
   b. If a Teams message ID is on the mapping → use it
   c. If not, deliver as a new top-level message. SlackBridge does not
      search for or guess which Teams message was the parent.
4. Deliver the reply via Microsoft Bot Framework with the Teams message ID
   embedded in the conversation ID:
       19:{channelId}@thread.tacv2;messageid={rootMessageId}

The conversation ID format above is a Microsoft Bot Framework requirement. Passing the message ID as a separate replyToId field is not enough on its own. The bridge handles this format internally; nothing on your end has to know about it.

When the parent's destination ID is missing

The Microsoft Bot Framework occasionally returns a successful 204 No Content response without a Teams message ID. When that happens, SlackBridge stores the Slack-side routing metadata anyway (message and channel IDs and a timestamp), but it has no Teams message ID to reply to.

A thread reply whose parent has no stored Teams message ID is delivered as a new top-level message in the Teams channel, and slack.thread.no_parent_mapping is logged. SlackBridge does not search the channel for a likely parent and does not score candidates: putting a reply under the wrong message is worse than putting it at the top level, and there is no way to confirm a guess.

The same rule applies in the other direction. A Teams reply whose parent has no stored Slack timestamp arrives in Slack as a new top-level message rather than inside a thread.

When the parent message was never bridged

If you reply to an old Slack message that predates SlackBridge being installed in your workspace, or whose bridging was paused at the time, the bridge has no mapping to look up. The same is true of any message older than seven days, because the timestamp-to-message-ID map is kept for seven days and then expires. Replying to a two-week-old thread therefore behaves exactly like replying to a message that was never bridged. In that case the reply is still delivered to Microsoft Teams, but as a new top-level message rather than as a reply. The log line slack.thread.no_parent_mapping records this so the cause is visible if you investigate later.

To re-thread an old conversation, the parent must be bridged first. Editing the original message does not do this: SlackBridge deliberately ignores Slack edits, so an edit produces no new bridged message. Post a new message instead, which becomes the root of a fresh thread on both sides.


How does Microsoft-Teams-thread-to-Slack-thread bridging work?

When a Microsoft Teams user posts a reply, the Microsoft Graph change-notification subscription delivers a payload containing a resource path that encodes both the parent message ID and the reply message ID:

/teams/{teamId}/channels/{channelId}/messages('PARENT_ID')/replies('REPLY_ID')

SlackBridge's webhook parses this resource path with a regex to extract the parent ID, then:

1. Match resource path: messages('PARENT')/replies('REPLY')
2. Extract replyToId = PARENT
3. Fetch the reply message from Microsoft Graph
4. Look up the message mapping by Teams parent ID → get the Slack thread_ts
5. Deliver the message to Slack via chat.postMessage with thread_ts set

The Slack chat.postMessage API uses the thread_ts parameter to attach a message to an existing thread. When thread_ts is set to the timestamp of the original Slack root, Slack threads the reply correctly.

If the bridge cannot find a Slack mapping for the Teams parent ID (for example, because the parent was a Teams message that was posted before bridging was active, or the mapping was evicted), the reply is delivered as a new top-level Slack message. This is the symmetrical behavior to the Slack-to-Teams case above.


What about reactions on threaded messages?

A reaction on a thread reply bridges by the same rules as a reaction on any other message. Slack reactions in the supported list arrive in Microsoft Teams as a readable bot message naming the reactor and the emoji; Teams reactions in the supported list arrive in Slack as native reactions on the corresponding Slack thread reply. See the SlackBridge emoji article for the full bidirectional map of 15 reaction types and 43 Slack shortcodes.

Reactions are processed as separate events from the message they react to, so a reaction can arrive after a small delay and still attach correctly.


What does Microsoft Teams do that SlackBridge cannot reproduce on the Slack side?

A few Teams threading behaviors do not have direct Slack equivalents:

Teams behavior What happens on the Slack side
Pinning a Teams message to the channel Not bridged (Slack pinning is a separate per-channel action)
"Reply with quote" (block-quoting the parent inline) The block-quoted text is bridged as plain text in the Slack reply body; the link back to the original is dropped
@mention of someone on the other platform, inside a reply Notifies them on the destination platform, exactly as in a top-level message, as long as you type their name as plain text rather than picking your own platform's mention chip. See Do @mentions translate?
Marking a reply as a "Reply broadcast" (sends to channel) Not bridged (the reply still arrives in the Slack thread normally; the broadcast flag is dropped)
Read receipts Not bridged. SlackBridge does not request the permissions needed to track who has read which message.

In each case the bridge errs on the side of preserving the message content rather than firing destination-side actions on a Slack user's behalf.


What does Slack do that SlackBridge cannot reproduce on the Teams side?

Slack behavior What happens on the Teams side
Also send to #channel (the "broadcast" checkbox on a Slack reply) The reply text is bridged into the Teams thread; SlackBridge does not separately re-post the reply at the channel root in Teams.
Slack call links and huddle links inside a thread Bridged as plain text URLs. Microsoft Teams does not auto-render Slack call links as call cards.
Slack workflow buttons inside a thread The button label is bridged as text; the button itself is not interactive in Teams (Slack interactivity is bound to Slack's interactive payloads, which Teams cannot dispatch back to).
Slack canvases linked from a thread Bridged as a plain link to the canvas URL. The canvas content is not rendered inline.

How do I verify threads are working in my own bridge?

Quick sanity check, on a mapping that is already active in both directions:

  1. Post a message in the bridged Slack channel (call it Message A).
  2. Wait for it to appear in the bridged Teams channel as Message A'.
  3. Reply to Message A in the Slack thread.
  4. The reply should appear inside the corresponding thread in Teams (under Message A'), not as a new top-level message.
  5. Reply to Message A' inside the Teams thread.
  6. The reply should appear inside the Slack thread.

If a reply ends up as a top-level message instead of inside the thread, the parent's destination message ID was not captured at bridge time. Posting a fresh root message and replying to that should re-thread cleanly. If you keep seeing top-level deliveries, contact SlackBridge support with the timestamps of the messages involved.


Frequently asked questions

If I reply in a Slack thread, does it appear in the Microsoft Teams thread?

Yes. A reply on a bridged Slack message is delivered to Microsoft Teams as a reply on the corresponding Teams root message. The threading is preserved end-to-end, so the conversation reads in the same order on both sides.

If I reply on a Microsoft Teams root message, does it appear in the Slack thread?

Yes. SlackBridge subscribes to thread reply events on the Teams side and bridges each reply to Slack with the matching thread_ts set, so replies land inside the original Slack thread rather than as new top-level messages.

How does SlackBridge know which Microsoft Teams message corresponds to a Slack message?

When SlackBridge bridges a message, it stores a mapping containing the Slack timestamp, the Microsoft Teams message ID, channel identifiers, and a non-reversible one-way fingerprint of the message (the readable sender name and message text are deliberately not stored). When a thread reply needs the parent's Teams ID, SlackBridge looks it up by the Slack timestamp. If no mapping carries a Teams message ID for that parent, the reply is delivered as a new top-level message rather than being guessed into a thread.

What happens if the original parent message wasn't bridged?

If the parent message in Slack predates SlackBridge being installed (or its bridging was paused at the time), the thread reply is still delivered to Microsoft Teams, but as a new top-level message rather than as a reply. SlackBridge logs slack.thread.no_parent_mapping in this case and continues. To re-thread an old conversation, the parent must be bridged first.

Why does Microsoft Teams sometimes show the bot's reply at the top level instead of inside a thread?

Microsoft's Bot Framework requires a specific conversation ID format to deliver a thread reply: 19:{channelId}@thread.tacv2;messageid={rootMessageId}. If SlackBridge cannot resolve the root message ID at delivery time, it delivers the message at the top level rather than failing. This does not repair itself: nothing later fills in the missing ID, so further replies to that same parent also arrive at the top level. Post a new message to start a thread that both sides can follow.

Are threaded reactions also bridged?

Reactions on threaded messages bridge with the same rules as reactions on top-level messages. See the emoji article for the full reaction-bridging map. Adding a reaction to a reply is treated as a separate event from the message it reacts to.

What is the maximum thread depth that SlackBridge bridges?

Both Slack and Microsoft Teams use a flat thread model: there is a root message and a flat list of replies. Neither platform supports replies to replies as a separate visual structure. SlackBridge follows the same model, so any reply on either platform attaches directly to the root.


Still need help?

If a thread is not bridging the way you expect, contact SlackBridge support with:

  1. The timestamp of the parent message on the source platform (Slack or Teams)
  2. The timestamp of the reply that did not bridge correctly
  3. Which platform the reply was sent on, and which platform you expected it to thread on
  4. Whether the parent was bridged in real time (i.e., posted after the bot was installed) or whether it predates the install

We aim to respond within one business day, and the message-mapping records associated with both timestamps are queryable internally for incident review (see Security → Audit Logging for how SlackBridge's tamper-evident audit trail is structured).

The Microsoft Graph permissions that make threading work are listed under What permissions does SlackBridge ask for, and why?: specifically ChannelMessage.Read.All on the Teams side and channels:history / groups:history on the Slack side.