Group Channel

Group Channel is a chat that provides close interactions among limited number of people. The group channel can be private or a public. A private group channel can let a user join the chat through an invitation by another user who is already a member of the chatroom. For 1-on-1 messaging, you can create a private group channel with two members. A public group chat can let a user join the chat without invitation. A group channel can consist of one to one hundred members by default setting. This default number of members can increase per request.

Users receive all messages from the group channels that they are a member of. And they can receive push notifications, typing indicators, unread counts and read receipts from these channels when they go offline. For more information, see the Push Notifications section which describes how to turn on and manage the push preference.


Choose a type of a group channel

With our JavaScript SDK, you can use a variety of behaviour related properties when creating different Group Channels. You can create a group channel after configuring these properties.

Private vs. Public

A Private group channel (default setting) can be accessed only by users that have accepted an invitation by an existing member of that group. On the other hand, a Public group channel can be accessed by any user without an invitation, like an open channel.

Ephemeral vs. Persistent

Messages sent in an Ephemeral group channel are not saved in SendBird infrastructure's database. As such, the old messages that scroll up beyond the user's display due to new messages cannot be retrieved. On the other hand, messages sent in a Persistent group channel (default setting) are stored permanently in the database.

1-on-1 vs. 1-on-N

A Distinct group channel can be reused for the same members. If a new member is invited, or if a member leaves the channel, then the Distinct property is disabled automatically. For example, when attempting to create new group channel with 3 members, A, B, and C, if a channel with same members already exists, a reference to the existing channel is just returned to who has attempted new channel.

Consequently, we recommend turning on the Distinct property in 1-on-1 messaging channels to reuse the existing channel when a user directly sends a message to a friend. If the property is turned off, a new group channel is created with the same friend even if there is a previous chat between them, and you can't see the old messages or data.


Create a group channel with additional information

A group channel can be created on demand by a user through the client SDK. Pass in two user IDs to create a 1-on-1 chat between two users.

You typically want a 1-on-1 chat to be Distinct. If the Distinct property is turned off, a user can create a new channel with the same friend even if there is a previous conversation between them. In this case, multiple 1-on-1 chats between the same two users can exist, each with its own chat history and data.

var userIds = ['John', 'Harry'];
// When 'distinct' is false
sb.GroupChannel.createChannelWithUserIds(userIds, false, NAME, COVER_URL, DATA, function(groupChannel, error) {
    if (error) {
        return;
    }

    console.log(groupChannel);
});

When creating a channel, you can also append additioanl information like cover image and description by specifying several arguments.

var userIds = ['John', 'Harry'];

sb.GroupChannel.createChannelWithUserIds(userIds, DISTINCT, NAME, COVER_URL, DATA, CUSTOM_TYPE, function(groupChannel, error) {
    if (error) {
        return;
    }

    console.log(groupChannel);
});
  • NAME: the name of a channel, or the channel topic.
  • COVER_IMAGE_OR_URL: the file or URL of the cover image, which you can fetch to render into the UI.
  • DATA: the String field which can be a description of the channel or structured information such as a JSON String for other purposes.
  • CUSTOM_TYPE: the String field that allows you to subclassify your channel.

You can get the cover image URL using getCoverUrl(), and update a channel's cover image by calling updateChannel().

Note: You can also create a group channel via the SendBird Platform API. If you want to control channel creations and member invitations on the server-side, use the Platform API.

Otherwise, you can configure GroupChannelParams and create a new channel with that like below.

var params = new sb.GroupChannelParams();
params.isPublic = false;
params.isEphemeral = false;
params.isDistinct = false;
params.addUserIds([ 'John', 'Harry']);
params.operators = ['Jay'];
params.name = NAME;
params.coverImage = FILE;
params.coverUrl = COVER_URL;
params.data = DATA;
params.customType = CUSTOM_TYPE;

sb.GroupChannel.createChannel(params, function(groupChannel, error) {
    if (error) {
        return;
    }

    console.log(groupChannel);
});

Invite users to a group channel as members

Only members of a group channel can invite new users into the channel. You can determine whether the newly invited user sees the past messages in the channel or not. In your Dashboard Settings - Messages section, there is an option to show channel history. If this option is turned on, new users can view all messages sent before they have joined the channel. If not, new users can see only messages sent after they have been invited.

Note: By default, Show channel history is turned on.

var userIds = ['John', 'Harry'];

groupChannel.inviteWithUserIds(userIds, function(response, error) {
    if (error) {
        return;
    }
});

Accept or decline an invitation from other user

A user who is invited to a group channel can accept or decline the invitation. If the invitation is accepted, the user joins the group as a new member and can start chatting with other members. If the user declines the invitation, it is cancelled.

var autoAccept = false;    // If true, a user will automatically join a group channel with no choice of accepting and declining an invitation.

sb.setChannelInvitationPreference(autoAccept, function(response, error) {
    if (error) {
        return;
    }
});


// In case of accepting an invitation
groupChannel.acceptInvitation(function(response, error) {
    if (error) {
        return;
    }
});

// In case of declining an invitation
groupChannel.declineInvitation(function(response, error) {
    if (error) {
        return;
    }
});

Join a public group channel as a member

Any user can join a Public Group Channel as a member without an invitation and chat with other members in the channel.

if (groupChannel.isPublic) {
    groupChannel.join(function(response, error) {
        if (error) {
            return;
        }
    });
}

Leave a group channel

If a user leaves the group channel, the user can't receive messages from the channel anymore.

groupChannel.leave(function(response, error) {
    if (error) {
        return;
    }
});

Retrieve a list of group channels

You can obtain a list of all group channels by creating a GroupChannelListQuery. The next() method returns a list of GroupChannel objects.

Note: You can also set an option to include empty channels with setIncludeEmpty(). Empty channels are channels that have been created but contain no sent messages. By default, empty channels are not included (displayed).

var channelListQuery = sb.GroupChannel.createMyGroupChannelListQuery();
channelListQuery.includeEmpty = true;
channelListQuery.limit = 20; // pagination limit could be set up to 100

if (channelListQuery.hasNext) {
    channelListQuery.next(function(channelList, error){
        if (error) {
            return;
        }

        console.log(channelList);
    });
}

Retrieve a group channel by its URL

Since a channel URL is a unique identifier of a group channel, you can use a URL to retrieve a channel instance. Store channel URLs to handle lifecycle or state changes in your app. For example, if a user disconnects from SendBird by temporarily switching to another app, you can provide a smooth restoration of the user's state using a stored URL to fetch the appropriate channel instance, then re-entering the user into the channel.

sb.GroupChannel.getChannel(channelUrl, function(groupChannel, error) {
    if (error) {
        return;
    }

    console.log(groupChannel);

    // Successfully fetched the channel.
    // Do something with groupChannel.
});

Hide a group channel from the list

The following code will allow you to hide specific group channels so that it is not included in the list of group channels when a list is retrieved. The hidden channels will re-appear in the list when a new message is delivered within those channels.

groupChannel.hide(function(response, error) {
    if (error) {
        return;
    }
});

Filter group channels by user IDs

To filter a channel search by user ID, call userIdsExactFilter or userIdsIncludeFilter. Given an example where a user (with the ID "User") is part of two group channels:

  • channelA: [ "User", "John", "Jay" ]
  • channelB: [ "User", "John", "Jay", "Jin" ]

An ExactFilter returns the list of channels containing exactly the queried userIDs.

var filteredQuery = GroupChannel.createMyGroupChannelListQuery();
filteredQuery.userIdsExactFilter = [ john, jay ];
filteredQuery.next(function(channels, error) {
    ...
    // Only 'channelA' is returned.
});

An IncludeFilter returns channels where the userIDs are included. This method returns one of two different results, based on the parameter queryType.

var filteredQuery = GroupChannel.createMyGroupChannelListQuery();
filteredQuery.userIdsIncludeFilter = [ john, jay, jin ];
filteredQuery.next(function(channels, error) {
    ...
    // Only 'channelB' that include the ids { John, Jay, Jin } as a subset is returned.
});

filteredQuery.queryType = sb.GroupChannelListQuery.QueryType.OR;
filteredQuery.next(function(channels, err) {
    ...
    // 'channelA' and 'channelB' that include { John }, plus 'channelA' and 'channelB' that include { Jay }, plus 'channelB' that include { Jin }.
    // Actually 'channelA' and 'channelB' are returned.
});

Send messages to a group channel

Upon entering a channel, a user can send messages of the following types:

  • UserMessage: text message sent by user.
  • FileMessage: binary message sent by user.

You can additionally specify a CUSTOM_TYPE to further subclassify a message. When you send a text message, you can additionally attach arbitrary strings via a data field. You can utilize this field to send structured data such as font size, font type, or a custom JSON object.

Delivery failures due to the network issues returns an exception. By receiving a callback within an implementation of sendUserMessage(), it is possible to display only the messages that are successfully sent.

channel.sendUserMessage(MESSAGE, DATA, CUSTOM_TYPE, function(message, error){
    if (error) {
        return;
    }

    console.log(message);
});

A user can also send any binary file through SendBird. There are two ways in which you can send a binary file: by sending the file itself, or by sending a URL.

By sending a raw file, you are uploading it to the SendBird servers. Alternatively, you can choose to send a file hosted in your own servers by passing in a URL that points to the file. In this case, your file is hosted in the SendBird servers, and downloaded through your own servers instead.

Note: If you upload your file directly, a size limit is imposed per file. This limit depends on your plan, and can be viewed from your Dashboard. No file size limit is imposed if you send a file message via a URL. Then the file isn't uploaded to the SendBird servers.

// Sending a file message with a raw file
channel.sendFileMessage(FILE, NAME, TYPE, SIZE, DATA, CUSTOM_TYPE, function(fileMessage, error){
    if (error) {
        return;
    }

    console.log(fileMessage);
});

// Sending a file message with a file URL
channel.sendFileMessage(FILE_URL, DATA, CUSTOM_TYPE, function(fileMessage, error){
    if (error) {
        return;
    }

    console.log(fileMessage);
});

channel.sendFileMessage(FILE_URL, NAME, TYPE, SIZE, DATA, CUSTOM_TYPE, function(fileMessage, error){
    if (error) {
        return;
    }

    console.log(fileMessage);
});

Note: To send metadata along with a file, you can populate the data field.


Receive messages through a channel event handler

Messages can be received by adding a channel event handler. A received BaseMessage object is one of the following three message types.

  • UserMessage: text message sent by user.
  • FileMessage: binary message sent by user.
  • AdminMessage: message sent by an admin through the Platform API.

UNIQUE_HANDLER_ID is a unique identifier to register multiple concurrent handlers.

var ChannelHandler = new sb.ChannelHandler();

ChannelHandler.onMessageReceived = function(channel, message){
    console.log(channel, message);
};

sb.addChannelHandler(UNIQUE_HANDLER_ID, ChannelHandler);

When the UI isn't valid anymore, remove the channel event handler.

sb.removeChannelHandler(UNIQUE_HANDLER_ID);

Mention other members in a group channel

Sometimes it needs to call the attention of some members in a group channel which the push notification is restricted. If you implement the following code, the mentioned members (up to 10) will be notified.

var params = new sb.UserMessageParams();
params.message = 'Hi, guys!';
params.mentionedUserIds = ['John', 'Harry', 'Jay', 'Jin'];

groupChannel.sendUserMessage(params, function(message, error) {
    if (error) {
        return;
    }
});

Load previous messages in a group channel

You can load previous messages by creating a PreviousMessageListQuery instance and calling load(). You can display these messages in your UI once they have loaded.

Note: Whether a user can load messages prior to joining the channel depends on your settings. In your Dashboard Settings - Messages section, there is an option to show channel history. If this option is turned on, new users can view all messages sent before they have joined the channel. If not, new users can see only messages sent after they have been invited.

var prevMessageListQuery = groupChannel.createPreviousMessageListQuery();
prevMessageListQuery.limit = 30;
prevMessageListQuery.reverse = true;
prevMessageListQuery.load(function(messages, error) {
    if (error) {
        return;
    }

    console.log(messages);
});

Past messages are queried in fixed numbers (30 in the above code). A new PreviousMessageListQuery instance loads the most recent n messages. The load() on the same query instance returns n messages before that. So if you store your query instance as a member variable, you can traverse through your entire message history.

Note: Before invoking load() again, you must receive the callback of load() first.


Load messages in a group channel by timestamp or message ID

You can retrieve a set number of messages starting from a specific timestamp. To load messages sent prior to the specified timestamp, use getPreviousMessagesByTimestamp().

groupChannel.getPreviousMessagesByTimestamp(TIMESTAMP, IS_INCLUSIVE, PREV_RESULT_SIZE, REVERSE, MESSAGE_TYPE, CUSTOM_TYPE, function(messages, error) {
    if (error) {
        return;
    }

    // A list of messages sent before timestamp is successfully retrieved.
    console.log(messages);
});
  • TIMESTAMP: the reference timestamp.
  • IS_INCLUSIVE: whether to include messages sent exactly at TIMESTAMP.
  • PREV_RESULT_SIZE: the number of messages to load. Note that the actual number of results may be larger than the set value when there are multiple messages with the same timestamp as the earliest message.
  • REVERSE: whether to reverse the results.
  • MESSAGE_TYPE: a BaseChannel.MessageTypeFilter object. The values are limited to MessageTypeFilter.ALL, MessageTypeFilter.USER, MessageTypeFilter.FILE, or MessageTypeFilter.ADMIN.
  • CUSTOM_TYPE: the custom type of the messages to be returned.

Note: To load messages sent after a specified timestamp, call getNextMessagesByTimestamp() in a similar fashion. To load results on either side of the reference timestamp, use getPreviousAndNextMessagesByTimestamp().

You can also retrieve a set number of messages starting from a specific message ID. To load messages sent prior to the specified message ID, use getPreviousMessagesById().

groupChannel.getPreviousMessagesByMessageId(MESSAGE_ID, IS_INCLUSIVE, PREV_RESULT_SIZE, REVERSE, MESSAGE_TYPE, CUSTOM_TYPE, function(messages, error) {
    if (error) {
        return;
    }

    // A list of messages, the IDs of which are prior to the specified message ID, is successfully retrieved.
});
  • MESSAGE_ID: the reference message ID.
  • IS_INCLUSIVE: whether to include messages sent exactly at MESSAGE_ID.
  • PREV_RESULT_SIZE: the number of messages to load. Note that the actual number of results may be larger than the set value when there are multiple messages with the same message ID the earliest message.
  • REVERSE: whether to reverse the results.
  • MESSAGE_TYPE: a BaseChannel.MessageTypeFilter object. The values are limited to MessageTypeFilter.ALL, MessageTypeFilter.USER, MessageTypeFilter.FILE, or MessageTypeFilter.ADMIN.
  • CUSTOM_TYPE: the custom type of the messages to be returned.

Note: To load messages sent after the specified message ID, call getNextMessagesById() in a similar fashion. To load results on either side of the reference message ID, use getPreviousAndNextMessagesById().


Update a message in a group channel

Users can update any of their own text and file messages sent. An error is returned if a user attempts to update another user's messages. In addition, channel operators can update any messages sent in the channel.

// In case of a user message
groupChannel.updateUserMessage(MESSAGE_ID, BODY, DATA, CUSTOM_TYPE, function(message, error) {
    if (error) {
        return;
    }
});

// In case of a file message
groupChannel.updateFileMessage(MESSAGE_ID, BODY, DATA, CUSTOM_TYPE, function(message, error) {
    if (error) {
        return;
    }
});

A onMessageUpdated() of a channel event handler will be invoked after the message is updated, and all members of the channel will be notified.

var handler = new sb.ChannelHandler();

handler.onMessageUpdated = function(channel, message) {
    ...
};

sb.addChannelHandler(UNIQUE_HANDLER_ID, handler);
});

Delete a message from a group channel

Users can delete messages. An error is returned if a user attempts to delete messages sent by others. Also channel operators can delete any messages in the channel.

groupChannel.deleteMessage(MESSAGE, function(response, error) {
    if (error) {
        return;
    }
});

A onMessageDeleted() of a channel event handler will be invoked after the message is deleted, and the result also notified to all other members in the channel.

var handler = new sb.ChannelHandler();

handler.onMessageDeleted = function(channel, messageId) {
        ...
};

sb.addChannelHandler(UNIQUE_HANDLER_ID, handler);

Clear chat history of a certain member in a group channel

Some users may want to clear their own chat history in select or all of their group channels for various reasons. By using the following code, you can help users clear their chat history and start new chat with other members in the group channels they have joined.

groupChannel.resetMyHistory(function(response, error) {
    if (error) {
        return;
    }
});

When a user is online, all data in the group channels they are a member of are automatically updated. However, when a user is disconnected from SendBird and reconnects later, you must call refresh() to update the channels with the latest information.

groupChannel.refresh(function(response, error) {
    if (error) {
        return;
    }
});

Retrieve a list of all members in a group channel

You can retrieve a list of members in a group channel using members.

groupChannel.members;

Members of the channel are automatically updated when a user is online. But when the user is disconnected from SendBird and reconnected, you must call refresh() to update the channels with the latest information. See the Refresh all data related to a group channel section for the sample code.


Retrieve members online status in an open channel

To stay updated on each member's connection status, call refresh() before calling members of a group channel object. You can then get each of the users' connection statuses by checking user.getConnectionStatus.

By using user.connectionStatus at each User object in the returned list, you can check user's current connection status. The connectionStatus has one of the following three values:

  • nonavailable: user's status information cannot be reached.
  • offline: user is disconnected from SendBird.
  • online: user is connected to SendBird.

Retrieve a list of banned or muted users in a group channel

You can create a query to get a list of banned or muted users in a group channel. This query is only available for users who are registered as operators of a group channel.

// In case of retrieving banned users
var bannedUserListQuery = groupChannel.createBannedUserListQuery();
bannedUserListQuery.next(function(users, error) {
    if (error) {
        return;
    }
});

// In case of retrieving muted users
var memberUserListQuery = groupChannel.createMemberListQuery();
memberUserListQuery.mutedMemberFilter = 'muted';
memberUserListQuery.next(function(users, error) {
    if (error) {
        return;
    }
});

Ban and unban a member in a group channel

Operators of a group channel can remove any members that behave inappropriately in the channel by using our Ban function. Users that are banned from a channel can join in the channel again after the time period set by the operators. The operators can ban and unban members in group channels using the following code.

sb.GroupChannel.getChannel(channelUrl, function(groupChannel, error) {
    if (error) {
        return;
    }

    // Ban and unban a member
    if(groupChannel.myRole === sb.Member.Role.OPERATOR) {
        groupChannel.banUser(USER, SECONDS, DESCRIPTION, function(response, error) {
            if (error) {
                return;
            }

            // Custom implementation for what should be done after banning.

        });

        groupChannel.unbanUser(USER, function(res, err) {
            if (error) {
                return;
            }

            // Custom implementation for what should be done after unbanning.
        });
    }
});

Note: You can also use banUserWithUserId() and unbanUserWithUserId() methods, instead of banUser() and unbanUser() methods, as they have the same functionalities. Please see our API reference on banUserWithUserId() and unbanUserWithUserID().


Mute and unmute a member in a group channel

Operators of a group channel can prohibit selected members from sending messages using our Mute function. Muted members will remain in the channel and view the messages, but will not be allowed to send any messages until the operators unmute them. The operators can mute and unmute members in group channels using the following code:

sb.GroupChannel.getChannel(channelUrl, function(groupChannel, error) {
    if (error) {
        return;
    }

    // Mute and unmute a member
    if(groupChannel.myRole === sb.Member.Role.OPERATOR) {
        groupChannel.muteUser(USER, function(response, error) {
            if (error) {
                return;
            }

            // Custom implementation for what should be done after muting.
        });

        groupChannel.unmuteUser(USER, function(response, error) {
            if (error) {
                return;
            }

            // Custom implementation for what should be done after unmuting.
        });
    }
});

Note: You can also use muteUserWithUserId() and unmuteUserWithUserId() methods, instead of muteUser() and unmuteUser() methods, as they have the same functionalities. Please see our API reference on muteUserWithUserId() and unmuteUserWithUserID().


Freeze and unfreeze a group channel

You can temporarily inactivate various functions of a group channel to stop members from chatting in the channel, and re-activate the functions so that the members chat with each other.

// In case of freezing a channel
groupChannel.freeze(function(response, error) {
    if (error) {
        return;
    }

    // Custom implementation for what should be done after freezing.
});

// In case of unfreezing a channel
groupChannel.unfreeze(function(response, error) {
    if (error) {
        return;
    }

    // Custom implementation for what should be done after unfreezing.
});