Back to Blog
Guide

Slack API: Get Users in a Channel With conversations.members, Tested

conversations.members returns the user IDs in a channel, bots included. We ran it on public and private channels with the bot inside and outside each, joined the IDs to names and emails, and hit a cursor that pointed at an empty page.

Slack Green Team
October 2, 2026
October 2, 2026
2 min read
Share:
slack api
developers
channels

To get the users in a Slack channel, call conversations.members with the channel ID. It returns user IDs only, bots included, so you join them to users.info for names and emails. We tested it on 2 October 2026 in our own workspace with a test app (bot scopes channels:read, groups:read, users:read, users:read.email) on four channels: public and private, with the bot inside and outside each. The bot could read every public channel, and every private channel it was in. The one it was not in returned channel_not_found.

What conversations.members returns

A call on our public channel #w1pm-public-in, where the bot is a member:

{"ok": true, "members": ["U0B7L4YK420", "U0C673JH6RY"], "response_metadata": {"next_cursor": ""}}

The second ID is the bot itself. Slack's own channel dialog shows the same channel differently. It counted 1 member and put the bot under a separate "Agents & apps" tab:

Slack channel details for #w1pm-public-in: tabs About, Members 1, Agents & apps 1; the Members tab lists only

So the API count and the number in the channel header differ by the number of apps in the channel. Filter bots out with the is_bot field from users.info, shown below.

Which channels the bot can read

We ran the same call with the bot token and with a user token (the owner, who is in all four channels):

ChannelBot tokenUser token
Public, bot is a member2 IDs2 IDs
Public, bot is not a member1 ID (works without joining)1 ID
Private, bot is a member2 IDs2 IDs
Private, bot is not a memberchannel_not_found1 ID
Channel ID that does not existchannel_not_foundnot tested
No channel parameterinvalid_arguments, [ERROR] missing required field: channelnot tested

For a private channel, channel_not_found means the bot is not in it, not that the ID is wrong. Invite the bot first (/invite @yourbot in the channel, or conversations.invite with a user token); our add a user to a channel test covers the invite errors. More on that error is in channel_not_found.

Never appear "away" on Slack again

Cloud-based. No downloads. Works 24/7 even when your laptop is off.

Names and emails for every member

conversations.members gives IDs. This script, run with the bot token in SLACK_BOT_TOKEN, looks each one up with users.info:

import os, sys
from slack_sdk import WebClient

client = WebClient(token=os.environ["SLACK_BOT_TOKEN"])
channel = sys.argv[1]

ids = []
for page in client.conversations_members(channel=channel, limit=200):
    ids += page["members"]                      # slack_sdk follows next_cursor for you

for uid in ids:
    u = client.users_info(user=uid)["user"]
    email = u["profile"].get("email", "-")      # needs users:read.email
    kind = "bot" if u["is_bot"] else "person"
    print(f"{uid}  {kind:6}  {u['real_name'] or u['name']:<20}  {email}")
print(f"{len(ids)} members")

Output for #w1pm-public-in (we masked the email):

U0B7L4YK420  person  sieun                 s****@virev.ai
U0C673JH6RY  bot     sglabw1pm             -
2 members

Bots have no email, so the script prints -. The email needs the users:read.email scope, and adding a scope to an installed app means reinstalling it. For a large channel, one users.list page returns many profiles at once and costs fewer calls than one users.info per member; see our users.list test.

On the private channel without the bot, the same script stopped with:

slack_sdk.errors.SlackApiError: The request to the Slack API failed. (url: https://slack.com/api/conversations.members)
The server responded with: {'ok': False, 'error': 'channel_not_found'}

Paging: a cursor can point at an empty page

conversations.members pages with limit and cursor. On #all-slack, after the bot joined, it had exactly 2 members. With limit=2:

{"ok": true, "members": ["U0B7L4YK420", "U0C673JH6RY"], "response_metadata": {"next_cursor": "dXNlcl9pZDoxMjIxMTEyMDU4NDg4Mg=="}}

Following that cursor returned:

{"ok": true, "members": [], "response_metadata": {"next_cursor": ""}}

A full page comes with a cursor even when nothing is left. Loop until next_cursor is empty, and do not treat an empty members list as an error. The cursor is base64 for user_id:12211120584882. Our pagination test covers the same pattern on other methods.

The other direction: users.conversations

To list the channels a user is in, call users.conversations. The types default caught us: without it, only public channels come back.

CallChannels returned
User token, no parameters6 public channels
User token, types=public_channel,private_channel9: the 6 public plus 3 private
Bot token, no parameters2: the channels the bot is in
Bot token, user=<owner ID>the owner's 6 public channels
Bot token, user=<owner ID>, types=public_channel,private_channel7: the 6 public plus the 1 private channel the bot is also in

A bot asking about a user sees that user's private channels only where the bot is a member too.

Always Active

Stop Jiggling Your Mouse.

Join hundreds of remote workers who never worry about their Slack status. Set it up once, stay green forever.

Related Articles

Guide

assistant.threads.setStatus vs agents.sessions.setStatus: Both Tested in Slack

We called assistant.threads.setStatus and agents.sessions.setStatus on a test app before and after turning on the agent feature, clicked the stop button, and timed how long the status line stays. Every response, the stop event, and what Slack showed.

Slack Green Team
Guide

Slack Slash Command Payload: Every Field, Responses, and response_url Limits

We caught the payload a slash command sends, answered it as ephemeral, in_channel, plain text and empty, posted to its response_url until it failed, and typed the command inside a thread. Every result is from a test app on 2 October 2026.

Slack Green Team
Guide

Slackbot MCP Client: We Connected a 17-Line MCP Server and Slackbot Called It

We wrote a one-tool MCP server, added it to a Slack app with the mcp_servers manifest field, switched it on in Slackbot and asked for the time. Every request Slackbot sent to the server, the permission prompt, and what Slackbot said when the server was down.

Slack Green Team