Quick Reference// Listen for real-time messages (register AFTER login)
CometChat.addMessageListener("LISTENER_ID", new CometChat.MessageListener({
onTextMessageReceived: (msg) => console.log(msg.getText()),
onMediaMessageReceived: (msg) => console.log(msg.getAttachment()),
}));
// Fetch message history
const request = new CometChat.MessagesRequestBuilder().setUID("USER_UID").setLimit(30).build();
const messages = await request.fetchPrevious();
// Cleanup (on component unmount)
CometChat.removeMessageListener("LISTENER_ID");
Key Points:
- Register listeners AFTER successful login
- Use unique listener IDs (duplicates overwrite)
- Always remove listeners on cleanup
Receiving messages in CometChat involves two parts. If you’re unfamiliar with message categories (message, custom, action, call) and types (text, image, video, etc.), review the Message Structure & Hierarchy guide first.
- Real-time messages - Listen for new messages while your app is running
- Message history - Fetch previous messages when loading a conversation
Real-Time Messages
Register a MessageListener to receive messages instantly:
const listenerID = "UNIQUE_LISTENER_ID";
CometChat.addMessageListener(
listenerID,
new CometChat.MessageListener({
onTextMessageReceived: (textMessage) => {
console.log("Text message received:", textMessage);
},
onMediaMessageReceived: (mediaMessage) => {
console.log("Media message received:", mediaMessage);
},
onCustomMessageReceived: (customMessage) => {
console.log("Custom message received:", customMessage);
}
})
);
As a sender, you won’t receive your own messages in real-time events. However, if logged in on multiple devices, other devices will receive the event.
Remove Listener
Always remove listeners when they’re no longer needed (e.g., when unmounting a component):
CometChat.removeMessageListener(listenerID);
All Message Events
CometChat.addMessageListener(
listenerID,
new CometChat.MessageListener({
// Message received
onTextMessageReceived: (textMessage) => {},
onMediaMessageReceived: (mediaMessage) => {},
onCustomMessageReceived: (customMessage) => {},
onInteractiveMessageReceived: (interactiveMessage) => {},
// Message updates
onMessageEdited: (message) => {},
onMessageDeleted: (message) => {},
// Typing indicators
onTypingStarted: (typingIndicator) => {},
onTypingEnded: (typingIndicator) => {},
// Read receipts
onMessagesDelivered: (messageReceipt) => {},
onMessagesRead: (messageReceipt) => {},
onMessagesDeliveredToAll: (messageReceipt) => {}, // Groups only
onMessagesReadByAll: (messageReceipt) => {}, // Groups only
// Transient messages
onTransientMessageReceived: (transientMessage) => {}
})
);
Message History
Fetch previous messages for a conversation using MessagesRequest.
One-on-One Conversation
JavaScript
TypeScript
Async/Await
const UID = "user_id";
const limit = 30;
const messagesRequest = new CometChat.MessagesRequestBuilder()
.setUID(UID)
.setLimit(limit)
.build();
messagesRequest.fetchPrevious().then(
(messages) => {
console.log("Messages:", messages);
},
(error) => {
console.log("Error:", error);
}
);
const UID: string = "user_id";
const limit: number = 30;
const messagesRequest: CometChat.MessagesRequest =
new CometChat.MessagesRequestBuilder()
.setUID(UID)
.setLimit(limit)
.build();
messagesRequest.fetchPrevious().then(
(messages: CometChat.BaseMessage[]) => {
console.log("Messages:", messages);
},
(error: CometChat.CometChatException) => {
console.log("Error:", error);
}
);
async function fetchMessages(uid, limit = 30) {
const messagesRequest = new CometChat.MessagesRequestBuilder()
.setUID(uid)
.setLimit(limit)
.build();
try {
const messages = await messagesRequest.fetchPrevious();
console.log(`Fetched ${messages.length} messages`);
return messages;
} catch (error) {
console.error("Failed to fetch messages:", error);
throw error;
}
}
// Usage
const messages = await fetchMessages("user123");
Group Conversation
const GUID = "group_id";
const limit = 30;
const messagesRequest = new CometChat.MessagesRequestBuilder()
.setGUID(GUID)
.setLimit(limit)
.build();
messagesRequest.fetchPrevious().then(
(messages) => console.log("Messages:", messages),
(error) => console.log("Error:", error)
);
Call fetchPrevious() repeatedly on the same request object to load older messages:
// Initial load
const messagesRequest = new CometChat.MessagesRequestBuilder()
.setUID(UID)
.setLimit(30)
.build();
// First page
messagesRequest.fetchPrevious().then((messages) => {
displayMessages(messages);
});
// Load more (on scroll up)
function loadMoreMessages() {
messagesRequest.fetchPrevious().then((messages) => {
prependMessages(messages);
});
}
// Initial load
const messagesRequest = new CometChat.MessagesRequestBuilder()
.setUID(UID)
.setLimit(30)
.build();
// First page
async function loadInitialMessages() {
try {
const messages = await messagesRequest.fetchPrevious();
displayMessages(messages);
return messages;
} catch (error) {
console.log("Error:", error);
throw error;
}
}
// Load more (on scroll up)
async function loadMoreMessages() {
try {
const messages = await messagesRequest.fetchPrevious();
prependMessages(messages);
return messages;
} catch (error) {
console.log("Error:", error);
throw error;
}
}
Missed Messages
Fetch messages that arrived while your app was offline.
const UID = "user_id";
const limit = 30;
const latestId = await CometChat.getLastDeliveredMessageId();
const messagesRequest = new CometChat.MessagesRequestBuilder()
.setUID(UID)
.setMessageId(latestId)
.setLimit(limit)
.build();
messagesRequest.fetchNext().then(
(messages) => console.log("Missed messages:", messages),
(error) => console.log("Error:", error)
);
async function fetchMissedMessages(UID) {
try {
const latestId = await CometChat.getLastDeliveredMessageId();
const messagesRequest = new CometChat.MessagesRequestBuilder()
.setUID(UID)
.setMessageId(latestId)
.setLimit(30)
.build();
const messages = await messagesRequest.fetchNext();
console.log("Missed messages:", messages);
return messages;
} catch (error) {
console.log("Error:", error);
throw error;
}
}
Use fetchNext() for missed messages (messages after a specific ID) and fetchPrevious() for message history (messages before current view).
Unread Messages
Fetch only unread messages:
User Conversation
Group Conversation
const messagesRequest = new CometChat.MessagesRequestBuilder()
.setUID(UID)
.setUnread(true)
.setLimit(30)
.build();
messagesRequest.fetchPrevious().then(
(messages) => console.log("Unread messages:", messages),
(error) => console.log("Error:", error)
);
const messagesRequest = new CometChat.MessagesRequestBuilder()
.setGUID(GUID)
.setUnread(true)
.setLimit(30)
.build();
messagesRequest.fetchPrevious().then(
(messages) => console.log("Unread messages:", messages),
(error) => console.log("Error:", error)
);
Search Messages
Search for messages containing specific text:
const messagesRequest = new CometChat.MessagesRequestBuilder()
.setUID(UID)
.setSearchKeyword("hello")
.setLimit(30)
.build();
messagesRequest.fetchPrevious().then(
(messages) => console.log("Search results:", messages),
(error) => console.log("Error:", error)
);
Advanced Search (available in Advanced & Custom plans) searches across message text, file names, mentions, and mime types. Enable it in Dashboard → Chats → Settings → General Configuration.
| Feature | Basic Search | Advanced Search |
|---|
| Text search | ✅ | ✅ |
| File name search | ❌ | ✅ |
| Mentions search | ❌ | ✅ |
| Mime type search | ❌ | ✅ |
Unread Message Count
For a Specific User
CometChat.getUnreadMessageCountForUser(UID).then(
(count) => console.log("Unread from user:", count),
(error) => console.log("Error:", error)
);
For a Specific Group
CometChat.getUnreadMessageCountForGroup(GUID).then(
(count) => console.log("Unread in group:", count),
(error) => console.log("Error:", error)
);
For All Conversations
CometChat.getUnreadMessageCount().then(
(count) => {
console.log("Users:", count.users); // { uid1: 5, uid2: 3 }
console.log("Groups:", count.groups); // { guid1: 10 }
},
(error) => console.log("Error:", error)
);
Exclude Blocked Users
const hideBlockedUsers = true;
CometChat.getUnreadMessageCount(hideBlockedUsers).then(
(count) => console.log("Unread count:", count)
);
Filter Options
The MessagesRequestBuilder supports various filters:
| Method | Description |
|---|
setUID(uid) | Filter by user conversation |
setGUID(guid) | Filter by group conversation |
setLimit(limit) | Number of messages to fetch (max 100) |
setMessageId(id) | Fetch messages around this ID |
setTimestamp(timestamp) | Fetch messages around this time |
setUnread(true) | Only unread messages |
setSearchKeyword(keyword) | Search in message content |
setCategory(category) | Filter by category (message, action, call, custom) |
setType(type) | Filter by type (text, image, video, etc.) |
setTypes(types) | Filter by multiple types |
setCategories(categories) | Filter by multiple categories |
hideReplies(true) | Exclude threaded replies |
hideDeletedMessages(true) | Exclude deleted messages |
setTags(tags) | Filter by message tags |
withTags(true) | Include tags in response |
setMentionsWithTagInfo(true) | Include mention details |
setMentionsWithBlockedInfo(true) | Include blocked user info in mentions |
Example: Filter by Type
const messagesRequest = new CometChat.MessagesRequestBuilder()
.setUID(UID)
.setLimit(30)
.setTypes(["image", "video"])
.setCategories(["message"])
.build();
Example: Exclude Replies and Deleted
const messagesRequest = new CometChat.MessagesRequestBuilder()
.setUID(UID)
.setLimit(30)
.hideReplies(true)
.hideDeletedMessages(true)
.build();
Message Object
Messages are returned as BaseMessage objects. Use instanceof to determine the type:
messages.forEach((message) => {
if (message instanceof CometChat.TextMessage) {
console.log("Text:", message.getText());
} else if (message instanceof CometChat.MediaMessage) {
console.log("Media URL:", message.getAttachment()?.getUrl());
} else if (message instanceof CometChat.CustomMessage) {
console.log("Custom data:", message.getCustomData());
} else if (message instanceof CometChat.Action) {
console.log("Action:", message.getAction());
}
});
Common Properties
| Property | Method | Description |
|---|
| ID | getId() | Unique message identifier |
| Sender | getSender() | User object of sender |
| Receiver | getReceiver() | User/Group object |
| Sent At | getSentAt() | Unix timestamp |
| Type | getType() | text, image, video, etc. |
| Category | getCategory() | message, action, call, custom |
| Read At | getReadAt() | When message was read |
| Delivered At | getDeliveredAt() | When message was delivered |
| Edited At | getEditedAt() | When message was edited |
| Deleted At | getDeletedAt() | When message was deleted |
React Implementation Example
Here’s a complete React hook for handling messages:
import { useEffect, useState, useCallback, useRef } from "react";
import { CometChat } from "@cometchat/chat-sdk-javascript";
export function useMessages(conversationId, conversationType = "user") {
const [messages, setMessages] = useState([]);
const [loading, setLoading] = useState(false);
const [hasMore, setHasMore] = useState(true);
const requestRef = useRef(null);
// Initialize messages request
useEffect(() => {
const builder = new CometChat.MessagesRequestBuilder()
.setLimit(30);
if (conversationType === "user") {
builder.setUID(conversationId);
} else {
builder.setGUID(conversationId);
}
requestRef.current = builder.build();
setMessages([]);
setHasMore(true);
// Load initial messages
loadMessages();
// Setup real-time listener
const listenerID = `messages_${conversationId}`;
CometChat.addMessageListener(
listenerID,
new CometChat.MessageListener({
onTextMessageReceived: (message) => {
if (isRelevantMessage(message)) {
setMessages((prev) => [...prev, message]);
CometChat.markAsRead(message);
}
},
onMediaMessageReceived: (message) => {
if (isRelevantMessage(message)) {
setMessages((prev) => [...prev, message]);
CometChat.markAsRead(message);
}
},
onMessageEdited: (message) => {
setMessages((prev) =>
prev.map((m) => (m.getId() === message.getId() ? message : m))
);
},
onMessageDeleted: (message) => {
setMessages((prev) =>
prev.map((m) => (m.getId() === message.getId() ? message : m))
);
}
})
);
return () => {
CometChat.removeMessageListener(listenerID);
};
}, [conversationId, conversationType]);
const isRelevantMessage = (message) => {
const sender = message.getSender().getUid();
const receiver = message.getReceiverId();
return sender === conversationId || receiver === conversationId;
};
const loadMessages = useCallback(async () => {
if (!requestRef.current || loading || !hasMore) return;
setLoading(true);
try {
const fetchedMessages = await requestRef.current.fetchPrevious();
setMessages((prev) => [...fetchedMessages, ...prev]);
setHasMore(fetchedMessages.length === 30);
// Mark last message as read
if (fetchedMessages.length > 0) {
CometChat.markAsRead(fetchedMessages[fetchedMessages.length - 1]);
}
} catch (error) {
console.error("Failed to load messages:", error);
} finally {
setLoading(false);
}
}, [loading, hasMore]);
const sendMessage = useCallback(async (text) => {
const receiverType = conversationType === "user"
? CometChat.RECEIVER_TYPE.USER
: CometChat.RECEIVER_TYPE.GROUP;
const textMessage = new CometChat.TextMessage(
conversationId,
text,
receiverType
);
const sentMessage = await CometChat.sendMessage(textMessage);
setMessages((prev) => [...prev, sentMessage]);
return sentMessage;
}, [conversationId, conversationType]);
return {
messages,
loading,
hasMore,
loadMore: loadMessages,
sendMessage
};
}
// Usage in component
function ChatScreen({ conversationId }) {
const { messages, loading, hasMore, loadMore, sendMessage } = useMessages(conversationId);
const [input, setInput] = useState("");
const handleSend = async () => {
if (!input.trim()) return;
await sendMessage(input);
setInput("");
};
return (
<div>
{hasMore && <button onClick={loadMore}>Load More</button>}
{loading && <div>Loading...</div>}
{messages.map((msg) => (
<div key={msg.getId()}>{msg.getText?.() || "Media message"}</div>
))}
<input value={input} onChange={(e) => setInput(e.target.value)} />
<button onClick={handleSend}>Send</button>
</div>
);
}
Next Steps