> For the complete documentation index, see [llms.txt](https://tools.docs.sendbird.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://tools.docs.sendbird.com/readme/chat/use-group-channel-features.md).

# Use Group channel features

Test these features in a [Group channel](/readme/chat.md#terms-used-in-these-tutorials):

* 1-to-1 channels
* Typing indicators
* Read receipts
* Replies in threads
* Files
* Reactions

## Before you begin

* Complete [Create test users](/readme/chat/create-test-users.md), and keep terminal A and terminal B open. Commands run against the app that's selected now. If you selected another app since then, [select your test app](/readme/quickstart.md#step-3-select-your-app) again.
* Your Sendbird account's Dashboard role must allow listing channel members. See [Your account and Chat users](/readme/commands/command-reference.md#your-account-and-chat-users).

## Step 1. Create a 1-to-1 channel

A 1-to-1 channel is a Group channel with two members. In terminal A, create one for Alice and Bob. Apps often use [distinct channels](/readme/chat.md#terms-used-in-these-tutorials) for 1-to-1 chats, so that two users always share one channel. In this tutorial, `--is-distinct false` creates a new channel every time instead. `--is-public false` makes the channel [private](/readme/chat.md#terms-used-in-these-tutorials), so users join it only by invitation.

```bash
sendbird --profile prod --json chat channel create --type group --name 'Tutorial DM' \
  --user-ids '["tutorial_alice","tutorial_bob"]' --is-distinct false --is-public false
```

`--user-ids` takes a JSON array of user IDs. The response includes the channel's `result.channel_url`. Copy that value. In the following commands, replace `<DM_CHANNEL_URL>` with it, without the angle brackets.

Each user must be `joined` before sending. Check each member's `state`:

```bash
sendbird --profile prod --json chat channel members list --type group --id <DM_CHANNEL_URL> --limit 20
```

A member you add when you create a channel can be `joined` right away or `invited`, depending on your app. In the response, each member has a `state`. `joined` means the user can send messages. `invited` means the user must accept the invitation first. If a user is already `joined`, skip that user's command below.

If Alice is `invited`, accept the invitation as Alice in terminal A:

```bash
sendbird --profile prod chat channel invitation accept --type group --id <DM_CHANNEL_URL> --as-user tutorial_alice
```

If Bob is `invited`, accept the invitation as Bob in terminal B:

```bash
sendbird --profile prod chat channel invitation accept --type group --id <DM_CHANNEL_URL> --as-user tutorial_bob
```

If you accepted an invitation, run the `members list` command again and check that both users are `joined`.

## Step 2. Watch typing and messages

In terminal B, start watching as Bob, and wait for the line that starts with `• ready`:

```bash
sendbird --profile prod chat channel watch --type group --id <DM_CHANNEL_URL> \
  --seconds 120 --max-events 100 --as-user tutorial_bob
```

The watch stops after two minutes or 100 events, whichever comes first. Switch to terminal A before it stops. If it stops before Alice sends, run it again.

In terminal A, send a typing indicator as Alice, then send a message:

```bash
sendbird --profile prod chat channel typing --type group --id <DM_CHANNEL_URL> \
  --seconds 3 --as-user tutorial_alice
sendbird --profile prod chat message send --type group --id <DM_CHANNEL_URL> \
  --message 'Are you available?' --as-user tutorial_alice
```

The second command prints `✓ Sent message` followed by the message ID. Copy the message ID. In the following commands, replace `<DM_MESSAGE_ID>` with it, without the angle brackets.

Bob's watch shows `typing` lines. Then it shows a `message received` line. The message ID at the end of that line matches the ID in terminal A.

## Step 3. Check read receipts

In terminal A, check whether the message is read:

```bash
sendbird --profile prod chat message receipts --type group --id <DM_CHANNEL_URL> \
  --message-id <DM_MESSAGE_ID> --as-user tutorial_alice
```

**Unread Count** is `1`, because Bob hasn't read the message yet. Watching a channel doesn't mark its messages as read. If it's `0`, another app or device that is signed in as Bob may have read the channel. You can continue, but the next check also shows `0`.

In terminal B, stop the watch with Ctrl+C, then mark the channel as read:

```bash
sendbird --profile prod chat channel read --type group --id <DM_CHANNEL_URL> --as-user tutorial_bob
```

The output starts with `✓ Marked read channel`. In terminal A, check the receipts again:

```bash
sendbird --profile prod chat message receipts --type group --id <DM_CHANNEL_URL> \
  --message-id <DM_MESSAGE_ID> --as-user tutorial_alice
```

**Unread Count** is now `0`.

## Step 4. Create a team channel

Steps 5 to 7 use a second Group channel, Tutorial team. This keeps the replies, file, and reaction separate from the 1-to-1 conversation.

In terminal A, create the channel:

```bash
sendbird --profile prod --json chat channel create --type group --name 'Tutorial team' \
  --user-ids '["tutorial_alice","tutorial_bob"]' --is-distinct false --is-public false
```

Copy `result.channel_url` from the response. In the following commands, replace `<TEAM_CHANNEL_URL>` with it, without the angle brackets.

Check each member's `state`, as in Step 1:

```bash
sendbird --profile prod --json chat channel members list --type group --id <TEAM_CHANNEL_URL> --limit 20
```

If Alice is `invited`, accept the invitation as Alice in terminal A:

```bash
sendbird --profile prod chat channel invitation accept --type group --id <TEAM_CHANNEL_URL> --as-user tutorial_alice
```

If Bob is `invited`, accept the invitation as Bob in terminal B:

```bash
sendbird --profile prod chat channel invitation accept --type group --id <TEAM_CHANNEL_URL> --as-user tutorial_bob
```

If you accepted an invitation, run the `members list` command again and check that both users are `joined`.

## Step 5. Reply in a thread

In terminal A, send a message as Alice:

```bash
sendbird --profile prod chat message send --type group --id <TEAM_CHANNEL_URL> \
  --message 'Please review this draft' --as-user tutorial_alice
```

Copy the message ID after `✓ Sent message`. In the following commands, replace `<PARENT_MESSAGE_ID>` with it, without the angle brackets.

In terminal B, reply to it as Bob:

```bash
sendbird --profile prod chat message reply --type group --id <TEAM_CHANNEL_URL> \
  --message-id <PARENT_MESSAGE_ID> --message 'I will review it' --as-user tutorial_bob
```

In terminal A, view the thread:

```bash
sendbird --profile prod chat message thread --type group --id <TEAM_CHANNEL_URL> \
  --message-id <PARENT_MESSAGE_ID> --limit 20 --as-user tutorial_alice
```

The output starts with `1 message`, which is Bob's reply. To view a thread, use the ID of the original message, not a reply.

## Step 6. Send a file

In terminal A, create a small file and upload it as Alice. The file is created in the folder where terminal A is running:

```bash
printf "%s\n" "Tutorial draft" > draft.txt
sendbird --profile prod chat message file --type group --id <TEAM_CHANNEL_URL> \
  --file draft.txt --file-name draft.txt --mime-type text/plain --as-user tutorial_alice
```

Copy the message ID after `✓ Sent message`. In terminal B, replace `<FILE_MESSAGE_ID>` with that ID, without the angle brackets, and read the message as Bob:

```bash
sendbird --profile prod --json chat message get --type group --id <TEAM_CHANNEL_URL> \
  --message-id <FILE_MESSAGE_ID> --as-user tutorial_bob
```

In the response, the file's `name` is `draft.txt` and its `size` is greater than zero.

## Step 7. Add a reaction

In terminal A, list the emoji keys registered in your app:

```bash
sendbird --profile prod chat sdk emoji list --as-user tutorial_alice
```

In terminal B, add a reaction as Bob to Alice's message from Step 5, then check it. Replace `<EMOJI_KEY>` with a key from the list, such as `sendbird_emoji_heart_eyes`, without the angle brackets:

```bash
sendbird --profile prod chat message reaction add --type group --id <TEAM_CHANNEL_URL> \
  --message-id <PARENT_MESSAGE_ID> --key <EMOJI_KEY> --as-user tutorial_bob
sendbird --profile prod --json chat message get --type group --id <TEAM_CHANNEL_URL> \
  --message-id <PARENT_MESSAGE_ID> --as-user tutorial_bob
```

In the response, `reactions` has an entry for the key you chose, and its `user_ids` includes `tutorial_bob`. Remove the reaction, then check again:

```bash
sendbird --profile prod chat message reaction remove --type group --id <TEAM_CHANNEL_URL> \
  --message-id <PARENT_MESSAGE_ID> --key <EMOJI_KEY> --as-user tutorial_bob
sendbird --profile prod --json chat message get --type group --id <TEAM_CHANNEL_URL> \
  --message-id <PARENT_MESSAGE_ID> --as-user tutorial_bob
```

`tutorial_bob` no longer appears in `reactions`. If no one else reacted, `reactions` is empty.

## Step 8. Clean up

If a watch is still running in terminal B, stop it with Ctrl+C. Then, in terminal A, delete the two channels and the file:

```bash
sendbird --profile prod chat channel delete --type group --id <DM_CHANNEL_URL> --yes
sendbird --profile prod chat channel delete --type group --id <TEAM_CHANNEL_URL> --yes
rm draft.txt
```

Keep Alice and Bob for the other tutorials, and [delete them](/readme/chat.md#delete-the-test-users) after you finish all the tutorials.

Next, follow [Invite, join, and leave channels](/readme/chat/invite-join-and-leave-channels.md).
