Go to Slack

Developing for Shared Channels

The rundown
Read this if:You're working with Enterprise Grid or multiple workspaces.
Read first:Managing Slack appsSubmission guidelines for the Slack App Directory
Read next:Developing for Enterprise Grid

Shared Channels allows you to collaborate with an external org!

The features described in this guide are still in development. Details mentioned are in flux and may change without prior notice. We will keep this guide updated as changes are made.

Shared Channels empower paid workspaces to seamlessly collaborate with people working at other companies, organizations, teams without leaving Slack — or your Slack apps behind.

While many apps, bots, and other integrations should work as expected with Shared Channels, you may face an occasional unexpected quirk as a result of multiple teams mingling in the same space, made more manageable with some nifty new APIs.

What are Shared Channels?

A shared channel is a bridge between teams needing to work together. Users converse seamlessly with individuals at other organizations with the same cozy ease they use communicating with their more immediate colleagues.

Instead of endless email threads or sidecar Slack workspaces filled with an organization's scattered business partners as guests, teams may now connect, chat, share files, and use apps together in a channel shared directly with another team.

Apps are already a core part of cross-team collaboration and integrate into shared conversations almost transparently... but to support shared channels with gusto, most developers will need to do a little bit of work.

Life before shared channels

Maybe you're just learning about shared channels or maybe it's years from when this documentation was written. Hello, time traveler. In either case, let's rewind to life before shared channels:

Before Shared Channels. With cats and dogs.

Disconnected. Disparate. Often duplicative. All remedied with shared channels:

After Shared Channels. With cats and dogs.

Your Slack app can be a part of all of this.

How Shared Channels work

In an ideal world, shared channels will work just like any other channel for users. Your app should also act predictably.

Messages and files

Both team's workspaces involved in a shared channel can read and send messages, share files, and access the history of shared channels.

Channel settings

Shared channels may have different settings on each workspace it's party to.

  • Channel names may differ. What's one workspace's #do-stuff is another workspace's #do-nothing. It's best to make no assumptions about channel names and stick only with IDs.
  • One workspace might set the channel as private. In another workspace it may be public. The implications to your product are yours to derive.
  • Data retention settings may differ between teams.

With all these differences in channel type settings, you must use the new Conversations API instead of existing APIs like channels.*, ims.*, and groups.*

Actually, we'd prefer you use conversations.* for all channel-like operations.

By default, only a team admin may start a shared channel. Permissions may also be extended to specific users, user groups, or everyone on their team.

API updates and additions

Be on the look out for minor differences in channel, message, user, team and related objects. When a channel can hold multiple teams within it, naturally you'll encounter messages and users originating from other teams.

Users may seem strange

Your app will receive messages and events from external members and strangers from a foreign team. There are some mild dangers. There are also some additional features in our suite of APIs.

A stranger in Shared Channels
An external member - In the profile, a member from a foreign team is marked with a square status indicator next to the user name.
  • External members are members on the other team that your application shares channel membership with.
  • Strangers are external members on the other team that your application does not have a shared channel in common; you can find out about these members when the other team mentions them in the shared channel or shares one of their messages or files into the shared channel.

The user type object (returned by methods like users.info) gives you additional user info. If the user is a stranger, who isn't in any shared channels, is_stranger flag is set true. There is only limited profile data allowed to be seen from a stranger.

Here's an example of a response from users.info:

    "ok": true,
    "user": {
        "id": "U0BNRNDKJ",
        "team_id": "T07QCRP7S",
        "name": "rex",
        "real_name": "Devon Rex",
        "profile": {
            "image_24": "https:\/\/.../11662770033.jpg",
            "email": "rex@catnip-inc.cat",
            "team": "T07QCRP7S"
            # all that other stuff
        "is_stranger": true

The APIs including Events API now returns an object including the source_team that indicates the source team ID of the external user.

Please note that when you specify a user, you need to use user id, instead of the username. With the new name-tagging feature, the username attribute cannot be relied on as a unique identifier, and will not work with "foreign" users via the API. For example, you cannot use chat.postMessage with a username set to a foreign user.

A bot user πŸ€– is able to DM users on both workspaces, as long as users are in a shared channel together.

Same channel, different setting

When a channel is shared, the channel ID remains the same but the name prefix can be different, depending on its setting- Even if the channel is set to private, the ID prefix changes from G to C (e.g. G1234567890 becomes C1234567890).

Since each team in the channel can independently decide if the channel is public or private on their end, so there are some changes with the APIs too:

  • The newly introduced conversations.* methods accept any types of channels.

  • The channel type object now includes the channel type info (public, private, etc.).

  • Now the channels.* methods accept both public and private channels with appropriate permission scopes.

The channel type object (which is returned by methods like conversations.info) tells you additional channel info. If the channel is shared, is_shared is set true. If it is a private channel or a group DM channel, the properties, is_private or is_mpim is set true, respectively.

Use these flags exclusively to determine the privacy and type of a given channel.

Example response from conversations.list:

    "ok": true,
    "channels": [
            "id": "C0A1NBPT3",
            "name": "product-qa",
            "is_channel": true,
            "created": 1491332036,
            "creator": "U0A379ZT2",
            "is_archived": false,
            "is_general": false,
            "is_shared": true,
            "is_org_shared": false,
            "is_member": false,
            "is_private": true,
            "is_mpim": false,
            "members": [
        { ...  },

Unsharing Channels

When a shared channel is unshared by the hosted workspace, both teams can still access channel history for all previous messages and activity. However, the channel in the disconnected workspace will be assigned a new ID, while the host workspace keeps the original channel ID. When you have apps using the workspace tokens in the shared channels, you will need to update the stored resource ID or transfer the configurations.

πŸ†• Sharing and unsharing private channels

Shared channels can be made private on a per-workspace basis. For instance, a public channel on one workspace can be shared with a private channel on another workspace. Use the Conversations API methods to work with the channels and accurately determine their privacy. channels.* and groups.* will not work private shared channels.

When a workspace's private shared channel becomes unshared, its channel ID remains C-prefixed (i.e. C1234567890 does not change back to G1234567890) although the channel is still private, making channel prefix an unreliable narrator in determining privacy.

New behavior to expect

In general, apps and internal integrations work between workspaces transparently. However, due to the nature of sharing, there will be restrictions in some scenarios, depending how the service behind the app is designed. For instance, a commercial app like Salesforce that's tied to their user accounts won't automatically give the access to the users on another workspace, and the Conversations API & users.info method should be used to determine appropriate data access.

Also, Slash commands are not shared — they are limited only to the team that has installed to their team workspace. Another team needs to install is independently to be able to use the commands.

When your app function is initiated by a slash command, only the team that installed it can invoke the command, and the rest can be shareable across the teams. For example, let's say, Catnip inc. has installed a voting app that is initiated with a command /vote. Users in the Catnip inc. can initiate a voting, while Woof inc. can only cast the vote and cannot create a new poll.

Example: a shared bot that initiates with a slash command

Slash Command behavior on Shared Channels

Bot users work similarly- bot users can be shared between workspaces, and each team members in a shared channel can send and receive DM to / from the bot user. However, the team that didn't install the bot in the first place has no access to the slash command.

Support strategies by feature

API Support strategies
Events API
  • Support events originated from external users in the shared channels.
  • No duplicated event triggering between shared channels
  • To see which teams the event is delivered, look for the values of the authed_teams property for the response.
  • Web API
  • Support external users in shared channels. Some user-related actions will not be permissible due to their external nature
  • Use users.info to retrieve additional information on cross-team user ID not found in users.list.
  • Incoming webhooks
  • Messages from incoming webhooks are visible to all members of a shared channel.
  • Incoming webhook can send DM only to the users on installed teams.
  • Slash commands
  • Slash command can be only invoked by users belonging to the workspace it is installed in.
  • Turn on entity resolution for mentioned users, allowing you to identity them by id, including on foreign teams.
  • Interactive messages
  • Handle action invocation by users from other teams, and letting them know if an action is not permissible due to their external nature.
  • Unfurls
  • When a user on the installing workspace posts a link in the shared channel. The link should be unfurled for the entire channel.
  • RTM
  • Support users from other workspace in shared channels where appropriate.
  • Message deliveries are duplicated in shared channels when installed on multiple joined workspaces due to the multiple socket connections.
  • Bot users πŸ€–
  • Bot users can DM all local users in the workspace they are installed in, and external users with a common shared channel.
  • Conversations API

    Developing with shared channels effectively requires using the new Web API methods we call the Conversations API.

    Known issues during the beta

    We're still working on Shared Channels. Some features are not yet available and it's likely you'll run into a bug or three.

    Here's what we know about:

    🚧 Channel IDs can become unstable in certain situations

    There are a few circumstances channel IDs might change within a workspace. If you can operate without depending on their stability, you'll be well-prepared for unfortunate hijinks.

    In the future, we'll mitigate this unexpected transition with appropriate Events API events or other solutions.

    In the meantime, be aware this might happen and use conversations.list regularly to monitor change for known #channel names if ID stability is important to you.

    🚧 It's hard to observe the lifecycle of a channel becoming and unbecoming shared

    For example, when one of the workspaces involved in a shared conversation chooses to unshare a channel, the original hosting workspace will retain the channel with the existing ID.

    However, the guest workspace will receive a copy of the channel and that channel will have a different ID.

    🚧 MPIM events tell little lies about channel types

    In a multiparty direct message channel ("MPIM") with a foreign user, events like member_joined_channel and member_left_channel may dispatch an incorrect value for channel_type.

    🚧 IM Object format is not yet consistent

    IM formats may differ from other channel objects for a while. We're working towards making all objects the same format.

    🚧 Occasional Events API oddities

    In some situations the authed_users and authed_teams fields may omit parties that should otherwise be listed. We'll resolve this as soon as we can!

    🚧 Unsharing channels

    When a channel becomes unshared, conversations.history access for the channel may become unreliable.

    Stay tuned for future updates!