Skip to main content
Quick Reference for AI Agents & Developers
// Send a thread reply
const textMessage = new CometChat.TextMessage(receiverID, "Reply text", receiverType);
textMessage.setParentMessageId(parentMessageId);  // Required for thread
await CometChat.sendMessage(textMessage);

// Fetch thread messages
const messagesRequest = new CometChat.MessagesRequestBuilder()
  .setParentMessageId(parentMessageId)
  .setLimit(30)
  .build();
const threadMessages = await messagesRequest.fetchPrevious();

// Hide thread replies in main chat
const messagesRequest = new CometChat.MessagesRequestBuilder()
  .setGUID(guid)
  .hideReplies(true)
  .build();

// Get reply count
const replyCount = message.getReplyCount();

// Listen for thread messages
if (message.getParentMessageId() === activeThreadId) {
  // This is a thread reply
}
Threaded messages are replies attached to a specific parent message. They help organize discussions by keeping related messages grouped together, especially useful in busy group conversations.
Available via: SDK | REST API | UI Kits


How Threads Work

┌─────────────────────────────────────┐
│ Parent Message (ID: 100)            │
│ "What should we do for the launch?" │
└─────────────────────────────────────┘

    ├── Reply 1 (parentMessageId: 100)
    │   "I think we should focus on social media"

    ├── Reply 2 (parentMessageId: 100)
    │   "Agreed, let's create a content calendar"

    └── Reply 3 (parentMessageId: 100)
        "I'll draft some posts by Friday"

Send a Thread Reply

Set the parentMessageId to send a message as part of a thread:
const receiverID = "UID";
const parentMessageId = 100;

const textMessage = new CometChat.TextMessage(
  receiverID,
  "This is a reply in the thread",
  CometChat.RECEIVER_TYPE.USER
);

textMessage.setParentMessageId(parentMessageId);

CometChat.sendMessage(textMessage).then(
  (message) => console.log("Thread reply sent:", message),
  (error) => console.log("Failed to send:", error)
);

Fetch Thread Messages

Retrieve all messages in a specific thread:
const parentMessageId = 100;
const limit = 30;

const messagesRequest = new CometChat.MessagesRequestBuilder()
  .setParentMessageId(parentMessageId)
  .setLimit(limit)
  .build();

messagesRequest.fetchPrevious().then(
  (messages) => console.log("Thread messages:", messages),
  (error) => console.log("Failed to fetch:", error)
);
Use fetchPrevious() to load older messages and fetchNext() to load newer ones. Maximum 100 messages per request.

Real-Time Thread Messages

Listen for new messages in a thread:
const listenerID = "THREAD_LISTENER";
const activeThreadId = 100;

CometChat.addMessageListener(
  listenerID,
  new CometChat.MessageListener({
    onTextMessageReceived: (message) => {
      if (message.getParentMessageId() === activeThreadId) {
        console.log("New thread message:", message);
      }
    },
    onMediaMessageReceived: (message) => {
      if (message.getParentMessageId() === activeThreadId) {
        console.log("New media in thread:", message);
      }
    },
    onCustomMessageReceived: (message) => {
      if (message.getParentMessageId() === activeThreadId) {
        console.log("New custom message in thread:", message);
      }
    }
  })
);

// Remove listener when done
CometChat.removeMessageListener(listenerID);

Hide Thread Replies in Main Chat

By default, thread replies appear in the main message list. To show only parent messages:
const GUID = "GUID";
const limit = 30;

const messagesRequest = new CometChat.MessagesRequestBuilder()
  .setGUID(GUID)
  .setLimit(limit)
  .hideReplies(true)  // Exclude thread replies
  .build();

messagesRequest.fetchPrevious().then(
  (messages) => console.log("Messages (without thread replies):", messages),
  (error) => console.log("Failed to fetch:", error)
);

Get Thread Reply Count

Check how many replies a message has:
const replyCount = message.getReplyCount();
console.log(`This message has ${replyCount} replies`);

Complete Implementation

class ThreadManager {
  constructor() {
    this.activeThreadId = null;
    this.threadMessages = [];
    this.listenerID = "thread-manager";
  }

  async openThread(parentMessageId) {
    this.activeThreadId = parentMessageId;
    this.threadMessages = [];
    
    this.setupListener();
    await this.fetchThreadMessages();
  }

  setupListener() {
    CometChat.addMessageListener(
      this.listenerID,
      new CometChat.MessageListener({
        onTextMessageReceived: (msg) => this.handleNewMessage(msg),
        onMediaMessageReceived: (msg) => this.handleNewMessage(msg),
        onCustomMessageReceived: (msg) => this.handleNewMessage(msg)
      })
    );
  }

  handleNewMessage(message) {
    if (message.getParentMessageId() === this.activeThreadId) {
      this.threadMessages.push(message);
      this.renderThread();
    }
  }

  async fetchThreadMessages() {
    const request = new CometChat.MessagesRequestBuilder()
      .setParentMessageId(this.activeThreadId)
      .setLimit(50)
      .build();

    try {
      this.threadMessages = await request.fetchPrevious();
      this.renderThread();
    } catch (error) {
      console.log("Failed to fetch thread:", error);
    }
  }

  async sendReply(text, receiverID, receiverType) {
    const message = new CometChat.TextMessage(receiverID, text, receiverType);
    message.setParentMessageId(this.activeThreadId);

    try {
      const sent = await CometChat.sendMessage(message);
      console.log("Reply sent:", sent);
    } catch (error) {
      console.log("Failed to send reply:", error);
    }
  }

  renderThread() {
    console.log(`Thread has ${this.threadMessages.length} messages`);
    // Update your UI here
  }

  closeThread() {
    CometChat.removeMessageListener(this.listenerID);
    this.activeThreadId = null;
    this.threadMessages = [];
  }
}

// Usage
const threadManager = new ThreadManager();
await threadManager.openThread(100);
await threadManager.sendReply("Great idea!", "group-123", CometChat.RECEIVER_TYPE.GROUP);
threadManager.closeThread();

Best Practices

  • Show reply count on parent messages to indicate threads exist
  • Use a slide-out panel or modal for thread views
  • Keep the parent message visible at the top of the thread
  • Show “View in thread” link when displaying thread replies in main chat
  • Use hideReplies(true) in main chat to reduce message count
  • Paginate thread messages for long threads
  • Cache thread messages when switching between threads
  • Update reply count on parent message when new replies arrive
  • Show typing indicators within thread context
  • Handle message edits and deletes in threads

Next Steps