Skip to main content
Keep important messages easy to find by pinning them to a conversation. A pinned message is visible to all participants of the conversation, along with who pinned it and when. Users can pin messages, unpin them, and fetch all pinned messages of a conversation. You can also listen to pin events in real-time. Let’s see how to work with pinned messages in CometChat’s Android SDK.
Pinning a message with the SDK requires the Pin Message feature to be enabled for your app. You can check its availability at runtime using the feature flag.

Pin a Message

To pin a message, use the pinMessage method and pass the ID of the message to be pinned. On success, the callback returns the updated BaseMessage with its pin attributes set.
Pinning is idempotent, and a message has a single pinner: re-pinning an already pinned message updates getPinnedBy() and getPinnedAt() to the most recent pinner rather than failing.
A just-sent message may not be pinnable or savable yet. On an app with moderation enabled, the server stamps a new message as moderation-pending and clears it a moment later. While it is pending, the call is rejected with ERR_MESSAGE_NO_ACCESS — the same code returned for a genuine permission refusal, so you cannot tell the two apart from the error alone.The window runs from send, not from the user’s tap, and clears within a few seconds. Do not disable the control on this error: by the time someone opens a menu and taps, moderation has usually finished. Prefer a retry or a transient “not ready yet” message over telling the user they lack permission. Moderation is configured per app, so this never reproduces on an app that has it switched off. (The CometChat UI Kits already withhold the Pin/Save options on a moderation-pending, disapproved, deleted or not-yet-sent message; this only concerns custom UI built directly on the SDK.)
Pinning is a moderation action and the server is the authority: a user without pin permission is rejected with ERR_PERMISSION_DENIED. There is no client-side role gate — the CometChat UI Kits show the Pin/Unpin option to every participant and surface a “you don’t have permission” toast on that error, so build your own UI the same way rather than trying to predict the verdict. Every participant can see pinned messages. Deleted messages cannot be pinned; deleting a pinned message automatically unpins it.

Unpin a Message

To unpin a message, use the unpinMessage method. Any participant with pin permission can unpin a message — not just the user who originally pinned it. On success, the callback returns the updated BaseMessage with its pin attributes cleared.

Fetch Pinned Messages

To fetch all pinned messages of a conversation, create a MessagesRequest with the setPinned(true) filter of the MessagesRequestBuilder. Setting a UID (for a one-on-one conversation) or a GUID (for a group) is mandatory — exactly one of the two. The returned list is sorted by the time of pinning, most recently pinned first.
The list is ordered by pin time, most recently pinned first — not by when the messages were sent. Render it in the order the SDK returns it. Page it with fetchNext() until a call returns an empty list; the cursor rides on pinnedAt instead of sentAt, and the SDK swaps it for you.

Check if a Message is Pinned

Every fetched or received message carries its pin state on the BaseMessage itself.
Editing a message preserves its pin. A message stores only its most recent pinner in getPinnedBy().

Real-time Pin Events

Register a MessageListener and override the pin callbacks. Each event delivers the full updated BaseMessage, so you can directly replace the message in your list. Today these callbacks fire on the acting user’s device when a pin or unpin succeeds. Delivery to other participants activates once server-side real-time delivery for pin events is rolled out — until then, other clients pick up pin changes on their next message fetch.
To stop listening, remove the listener with CometChat.removeMessageListener(listenerID).

Pin Limit

A conversation holds a capped number of pins, configurable per app. Read the cap rather than hard-coding it — it is tenant-overridable and will drift.
Both are synchronous and never throw. They return Settings.LIMIT_UNSPECIFIED (-1) when the app settings carry no value or when they are called before init() completes — show generic copy in that case rather than guessing a number. getSystemPinMessageLimit() is the separate cap for admin/global pins: system pins do not consume a user’s allowance, so the two budgets are enforced independently. When the limit is breached, the SDK surfaces the server error through onError, and the applicable limit is carried in the exception’s errorParams so you can tell the user the actual number without a second call.

Error Handling

Feature Availability

Check whether the Pin Message feature is enabled for your app before showing pin actions in your UI. The method is synchronous and safe to call from the UI layer.

Next Steps

Save A Message

Bookmark a message privately, across conversations

Pin A Conversation

Pin a conversation to the top of the list

All Real Time Listeners

Every listener the SDK exposes, in one place

Additional Message Filtering

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