Time dependent information users need to jump in and out of conversations and easily find their place.
Read receipts and unread message counts in SendBird
Read receipts and unread message counts enable users to navigate 1-on-1 and group conversations easily and asynchronously. They let users know when another user has caught up with the conversation and let users easily navigate to the messages they have missed since their last interaction.
A read receipt is a timestamp of when each user last read any messages in a group channel (i.e. a 1-on-1 or group conversation).
A read receipt’s timestamp is the moment in time that GroupChannel.markAsRead()was called for an individual channel member. It has an event handler and can be listened to when the handler updates.
Unread message count is the number of messages a user has not read in a group channel.
The unread message count applies to three scenarios for individual users:
- The total number of unread messages in a group channel
- The total number of unread messages in all group channels
- The number of group channels containing unread messages
Which apps should use read receipts and unread message counts?
These features are invaluable for users chatting in real time or asynchronously. In both cases, these two features help users understand the current state of the conversation and catch up quickly. They answer questions for the user like “Has everyone read my message?” and “What messages do I need to read now? What did I miss?”
For businesses where chat and messaging is a main channel for communicating with users, read receipts and unread message counts provide your user and company rep with information that can set users at ease and help reps stay accountable.
If a user asks a question to your business, they’ll want to know if it has been read so they can be at ease as the rep responds. Typing indicators are also crucial here. If a user opens your app later, then unread message counts let them know that they have a response waiting and it indicates where they can read it.
Use-cases for read receipts and unread message counts
Every application will want to implement unread message count and at least an option for read receipts because it provides basic information about a conversation to users. Most users expect these features in their chat.
Read receipts and unread message counts apply only to group channels in SendBird — that is, private 1-on-1 messaging and group chat. Open channels do not support read receipts and unread message counts.
These features have particular value for
- Online communities
- Apps with user-to-user messaging like gaming apps
- Businesses that communicate directly with users through an expert or advisor such as a healthcare concierge, financial advisor, customer support agent, counselor, or other expert
- On-demand services or any app that requires a timely delivery of services or goods
- Peer marketplaces, where communication is necessary for buying and selling
Implementing read status for a single message
In this and the following sections, the guide gives you the key concepts and implementation to create a read status for a single message that indicates how many members of a group channel have NOT read that message.
The read number 1 in the badge above indicates that at least one channel member has not read the current user’s message.
In order to implement this feature, the rest of this guide covers the following:
- Key terms: read message, unread message, unread message count, read receipt
- When to call markAsRead() and important cases
- Retrieving key information using on MarkAsRead()
- Implementing read status for a single message using getUnreadMembers()
Key terms: read message, unread message, unread message count, read receipt
What is a ‘read message’ in SendBird?
- SendBird provides the GroupChannel.markAsRead() method that can be called on the channel object
- All messages in a channel when GroupChannel.markAsRead() is called are considered read messages.
- It is up to the implementation to decide when this method is called.
Note: Individual message objects are not marked as read; instead, when GroupChannel.markAsRead() is called, all messages in a channel are marked as read.
What is an ‘unread message’ in SendBird?
- An unread message is any message added to a channel before GroupChannel.markAsRead() is called.
- Once GroupChannel.markAsRead() is called, all additional messages added after the call are considered as unread.
What is an unread message count?
- There are a few types of unread message counts for a current user (group channels only):
- The total number of unread messages in a channel
- The total number of unread messages in all channels
- The number of channels containing unread messages
Note: Unread message counts will only work when you apply the markAsRead method. Call markAsRead as soon as the user joins a channel for the first time so the unread message count begins counting from that call. Otherwise, unread message counts will remain at zero.
What is a ‘read receipt’ in SendBird?
- A read receipt indicates when a user has read the messages in a channel. It can be either
- A simple confirmation that the channel member at user_id read the messages in a channel, or
- A confirmation that user_id read the messages in a channel at a timestamp indicating when each user last read a message in a channel
- A read receipt represents the moment that GroupChannel.markAsRead() was called for an individual channel member.
- A read receipt has an event handler that you can listen to for updates
When to call markAsRead() and important cases
To maintain the most up-to-date and accurate read status for messages for each member in a group channel, you should call the markAsRead() method when any one of the members read messages in the channel. A member could read channels when they enter the channel from a channel list or bring the opened channel view into active focus on the screen (after being in the background).
When you call markAsRead(), the SendBird server updates the number of the current user’s unread messages in both the current group channel and in all joined channels. The server then notifies the change in read status to all the other channel members’ client apps in various ways depending on the platform.
Because markAsRead()marks as read all unread messages in the channel, the time you call it has important ramifications.
You can apply three different strategies. Call markAsRead()…
- Once the user opens the channel
- Marks all messages read when the user enters the channel, but does not guarantee that the user has viewed all messages
- After the user reaches the head of the message thread
- Marks all messages read after the user scrolls through the new messages. At minimum, the user has seen all the messages
- When the user manually marks messages as read
- This gives the user the option to mark messages as read, but it is a manual solution that might be too tedious for users.
For iOS and Android, capturing when the user interacts with a view of the messages is straight forward.
Here are five cases to consider when calling GroupChannel.markAsRead() for all platforms.
Case 1: When a user first joins a channel regardless of viewing the channel message view.
This case is extremely important.
- Any historical messages in a channel will not be counted automatically when a new user joins a channel. If you’d like to have an unread message count at this time, you can retrieve the total number of messages in a channel via Platform API and use it as an unread message count
- After they join the channel, the user’s unread message count will continue to be zero, even as new messages are added.
- To start incrementing the new members unread message count apply GroupChannel.markAsRead() either by the SDK or Platform API (Mark all messages as read).
Case 2: User opens a channel message view for the first time during a session
- Track which channel or channels are visible in the UI
- Call GroupChannel.markAsRead()
- When there’s successful button click, if there are multiple channels.
- When there’s a view or window onload event.
Case 3: A message is added to the channel message view that the user is looking at
- Listen for the new message. Then check if the channel message view is in focus
- If it’s in focus, call GroupChannel.markAsRead()
Note: For multi-screen environments, this may be difficult to achieve because the message stream may be visible and read by the user, but the window may not be in focus.
Case 4: User returns to a channel message view after focusing on a different view
- Consider setting a global variable newMessages to true when new messages arrive in the current channel
- Detect when the user returns to the channel message view
- If newMessages variable is true, when the user returns to the channel message view
- Call GroupChannel.markAsRead()
- Set newMessages to false and wait for the next new message
- Consider accounting for conditions when the user leaves the channel message view
- The user moved to a different in-app tab
- The user moved to a different application
- User’s screen window is scrolled up or down (See Case 4)
- On a desktop, laptop, or tablet: the user moved to a different window
Case 5: When the user scrolls up to see older messages.
- Throttle calls to GroupChannel.markAsRead() during scrolling events. Only call it intermittently, if the user is scrolling older messages
CAUTION: Calling markAsRead() on scrolling events can result in repeated calls to GroupChannel.markAsRead(). Unthrottled repeated calls to this function will result in reaching SendBird’s rate limit. This will cause the markAsRead() and other message functions to stop.
Retrieving key information using on MarkAsRead()
In the background, the onMarkAsRead method stores a point in time on the channel object for each user. SendBird then uses that point in time to determine whether a message has been added to the channel after it.
SendBird stores markAsRead timestamps for each user on the cachedReadRecieptStatus on individual channels.
According to when you call onMarkAsRead, you can extrapolate the following information by comparing the mark-as-read time to the message-creation time:
- Array of members who read a message
- Returns an array of channel members, except the current user and the message sender
- Array of members who did not read a message
- Returns an array of channel members, except the current user and the message sender
- Array of members’ read status
- Does not include the current user
- The number of members who did not read a message
Implementation with getUnreadMembers()
There are three important cases for checking whether a user’s sent message is unread or read:
- When other users read a message in realtime
- For this, apply a channel event listener
- Whenever the current user enters the channel
- Check the channel message list
- When the current user sends a message
- Check the message that the user has just sent
Case 1: When other users read a message in realtime
- Add a channel event listener to listen for the moment when markAsRead is called by the devices of other users
- If you want to keep track of who has read a new message, we recommend using getReadMembers() inside the onReadReceiptUpdated() method, which is a part of the channel listener family
- Add the above listener after initializing SendBird
- Next, filter incoming events according to the channel being viewed
- The listener receives a callback from the SendBird servers when a member of the same channel as the current user has read any message within the application
- Once the event handler is triggered you should pass the newly received incoming message object via the onReadReceiptUpdated() to the relevant method below:
Case 2: Whenever the current user enters the channel
- Consider the case when the sent messages of a user have their read status changed while the user is away from the channel
- For this case, as the user opens the channel message view, fetch the relevant messages for that channel. Next, iterate each message and pass it to the processUnreadMessageCount function from above.
Case 3: When the current user sends a message
- Consider the case when users periodically enter and leave the channel. When the current user sends a message, it is worth collecting the latest information for that message to see whether users entering or exiting the channel read the message
- To implement this, consider that there is a callback when a user sends a message using groupChannel.sendUserMessage
- When the callback returns, call groupChannel.getUnreadMemebers() and pass in the callback message
- processOneUnreadMessageCount might look like the following, where the unreadMessageCountList from above is updated with the latest message using the message id
Update the UI to display an unread message counter
Using the above example it is possible to provide additional information about an individual message to the current user.
Now, using the unreadMessageCountList we created previously, it is possible to apply an unread message counter to each of the messages sent by a user. The below image reproduces a sample UI.
To accomplish this, check the unreadMessageCountList items against the currentMessageList each time the channel message view renders to see the unread message counter for each message.
Implementing read status is at your fingertips
Users regard read status as a necessary feature of any messaging app, perhaps, so much so that they take for granted that most apps have it. With SendBird’s flexible API and SDK, you can build a robust read status that fits your application and use case—from an individual message to a channel unread message count.