Skip to main content
Thread subscription gives users control over thread noise. A user can subscribe to a message thread to be notified of future replies, or unsubscribe to mute it. The server subscribes a user to a thread automatically when they start it, reply in it, or are @-mentioned in it — and they can explicitly subscribe to any parent message, even one that has no replies yet.
Thread subscription builds on Threaded Messages. A thread is identified by the ID of its parent message — there is no separate thread ID.

How state works

The SDK keeps no subscription state of its own. There is no cache and no listener to reconcile:
  • Every message fetch asks the server for the flag, and it arrives on the message — read it with message.isThreadSubscribed().
  • subscribeToThread() and unsubscribeFromThread() resolve when the server has accepted the change. The resolved promise is the acknowledgement.
Your app owns the resulting UI state. That means you decide when to flip a toggle optimistically, and you decide what a thread’s state is before you have fetched it.

Subscribe to a Thread

Use subscribeToThread() with the ID of the thread’s parent message. The call is idempotent — subscribing to a thread the user already follows succeeds silently. Subscribing to a message with zero replies is allowed; the user is notified when the first reply arrives.

Unsubscribe from a Thread

Use unsubscribeFromThread(). This is idempotent too — unsubscribing from a thread the user does not follow succeeds silently.
Unsubscribing hard-deletes the server row, so a thread inbox built with ThreadsRequest must drop that row rather than mark it unfollowed. It is also not sticky: replying in the thread, or being @-mentioned in it, re-subscribes the user.

Read the Subscription State

Every message fetch the SDK makes asks the server for this flag, so any message you obtained from MessagesRequest or getMessageDetails() carries it.
A message delivered over the socket carries no flag and therefore reads false. That is not a claim that the user is unsubscribed — it means nobody asked. When you need certainty for a thread you have not fetched (a deep link, for instance), fetch the parent message with CometChat.getMessageDetails() and read the flag off the result.

You are subscribed to your own messages

Sending a message subscribes you to the thread it may later grow — there is nothing to call. The message comes back with threadSubscribed: true, both in the send response and on later fetches, and only for you: the flag is per-viewer, so the same message reads false for everybody else until they subscribe themselves. That default is what makes the flag meaningful on your own messages. Since it starts out true, a false on a message you sent — read from a fetch, not the socket — is not silence. It means you unsubscribed, and nothing should quietly put you back. This only holds for a message you sent and obtained from a fetch. On anyone else’s message, or on anything socket-delivered, false still just means the server was not asked.

Keeping your own copies in sync

The same thread can be represented by several message objects at once — a row in the message list, the header of an open thread view, an entry in a thread inbox. Because the SDK caches nothing, use setThreadSubscribed() to align the copies you hold once you know the answer:
setThreadSubscribed() is local only — it changes the object in memory and sends nothing to the server. Use subscribeToThread() / unsubscribeFromThread() to change the actual subscription.

Reacting to Replies

A thread reply is an ordinary message with parentMessageId set, delivered through the standard MessageListener like any other message. There is no separate thread listener.
Using MessageListener also gets you onMessageEdited and onMessageDeleted for replies, which a thread-only channel would not. Your own replies do not arrive on a listener — bump your thread row from the sendMessage() promise instead.

Fetch the Threads a User Participates In

Use ThreadsRequest to build a thread inbox. Every returned thread is one the logged-in user is subscribed to.
Scope the inbox to a single conversation with setUid() or setGuid(). Call fetchNext() again on the same object to page, and check hasMore() before doing so.
ThreadsRequestBuilder spells these setUid() / setGuid()not the setUID() / setGUID() used by MessagesRequestBuilder. The two are mutually exclusive; set at most one.

Reading a thread row

Each row is a MessageThread — enough to render an inbox without fetching the parent message separately.
getUnreadReplyCount() returns null, not 0, when the count is unknown. Treat null as “no badge” rather than as zero unread.

Next Steps

Threaded Messages

Send and fetch replies inside a thread

Mentions

@-mentions, which auto-subscribe a user to a thread

All Real Time Listeners

Every listener the SDK exposes, in one place

Save A Message

Bookmark a message privately, across conversations