Skip to main content
Available from Chat SDK v5.0.7. These APIs require cometchat_sdk v5.0.7 or later. See Setup to upgrade.
Saving bookmarks a message for the logged-in user. Unlike a pin, a save is private and cross-conversation: nobody else is notified or can see it, no role is required, and the saved list spans every conversation the user is part of — their own messages and everyone else’s.
savedAt is per-viewer. It is only ever populated in the acting user’s own context — you will never see another user’s saves on a message.

Save a Message

Call saveMessage() with the message’s ID. On success, onSuccess receives the full updated message, with savedAt set.
Saving is idempotent — saving an already saved message succeeds rather than failing.

Unsave a Message

Call unsaveMessage(). The returned message comes back with savedAt cleared to null.

Fetch Saved Messages

Build a MessagesRequest with the saved field of the MessagesRequestBuilder set to true. The saved list is user-level, so unlike the pinned list you do not set uid or guid — leaving both unset is what makes it cross-conversation.
The list is ordered by save time, most recently saved first — not by when the messages were sent. Call fetchPrevious() again on the same object to page through older entries; fetchNext() needs a message ID or timestamp cursor and fails with ERR_FILTERS_MISSING without one. The setSaved(true) setter is equivalent to the saved field. Because the list spans conversations, every row carries its own context — use conversationId, receiverType and receiverUid to route a tap on a saved message back to the right conversation. For a one-on-one message the logged-in user received, receiverUid is their own UID, so open the conversation with sender instead.

Check if a Message is Saved

A null savedAt means the logged-in user has not saved the message.

Real-time Save Events

Because saves are private, save events reach only the logged-in user’s own devices. Register a MessageListener using addMessageListener() and override the onMessageSaved() and onMessageUnsaved() callbacks.
In Flutter, the device that performed the save also receives these callbacks — the SDK fans them out locally as soon as the call succeeds and drops the server’s echo of the same action. The user’s other devices receive them over the socket. Update your saved list from the listener alone and you cover both.

Save Limit

A user may save a capped number of messages across all conversations. Read the cap rather than hard-coding it.
getSavedMessagesLimit() is synchronous and returns null when the backend did not serve a limit — show generic copy in that case rather than guessing a number.

Error Handling

saveMessage() and unsaveMessage() report failures through onError with a CometChatException. Branch on e.code rather than the message text: Saving is per-user, so there is no role gate: any participant can save a message they have access to, up to the cap.

Feature Availability

Check whether Save Message is enabled for your app before showing save actions. isSaveMessageEnabled() is synchronous and never throws.
When neither the login payload nor the app settings carry the flag, isSaveMessageEnabled() returns true, so the feature is not disabled on a backend that predates the flag.

Next Steps

Pin A Message

Highlight a message for everyone in a conversation

Pin A Conversation

Pin a conversation to the top of the list

Retrieve Conversations

Fetch and order the conversation list

Additional Message Filtering

Filter messages by saved, pinned, type, tags and more