Skip to main content
Available from Chat SDK v4.1.9. These APIs require CometChatSDK v4.1.9 or later.
Let users keep their most important chats at the top of the list. Pinning a conversation is per-user — it changes the order of the acting user’s own conversation list, other participants do not see it, and it syncs across that user’s devices. A conversation can also be pinned globally for everyone by the app itself (a system pin). Let’s see how to work with pinned conversations in CometChat’s iOS SDK.
Pin Conversation requires the features.ux.conversations.pinned.enabled flag, which is not seeded in any plan and must be mapped per app. Until it is, every call fails with ERR_FEATURE_NOT_ACCESSIBLE. Gate your UI on the feature flag before showing the control.
This is separate from an admin-global pin, which is managed from the CometChat Dashboard and shows for every user. Those cannot be created or removed from the SDK, only observed.

Pin a Conversation

To pin a conversation, use the pinConversation method. Pass the UID of the other user (for a one-on-one conversation) or the GUID of the group, along with the matching conversation type. On success, the callback returns the updated Conversation with its pin attributes set.
Pinning is idempotent — pinning an already pinned conversation succeeds rather than failing.
A conversation that has never been messaged, or that is hidden, cannot be newly pinned — the call fails with ERR_CONVERSATION_NOT_ACCESSIBLE. Pin from a conversation that already exists in the list.

Unpin a Conversation

To unpin a conversation, use the unpinConversation method with the same parameters. On success, the callback returns the updated Conversation with pinnedAt cleared back to 0.
A user cannot unpin a system pin (a conversation pinned globally by the app) — the server rejects the call. Check pinnedBy for app_system and hide the unpin action rather than relying on the round-trip to fail.
Both callbacks fire on a background thread. Dispatch to the main queue before updating your UI.

Fetch Pinned Conversations

The default conversation list is already pin-ordered by the server: admin-global pins first, then the user’s own pins, then everything else. Pinned rows count toward the page limit rather than being added on top of it. Fetch it as you normally would and no extra filter is needed. To fetch only pinned conversations, use the set(pinnedBy:) filter of the ConversationRequestBuilder. Pass both to get every pinned conversation. These are plain strings — there is no constant to import.
The match is exact and case-sensitive, and an unrecognised value is dropped silently rather than raising. set(pinnedBy: ["Me"]) leaves nothing behind, the filter is omitted entirely, and you get the full conversation list back — not an error, and not a pinned-only list. Passing an empty array does the same thing.

Check if a Conversation is Pinned

Every fetched Conversation carries its pin state in two fields:
Presence of the timestamp is the boolean. There is no separate isPinned or isSystemPinned flag on iOS — check pinnedAt != 0, and compare pinnedBy with "app_system" for a system pin.
When a conversation carries both a system pin and the user’s own pin, the system pin takes precedence and sorts above the user’s pins.

Real-time Conversation Pin Events

Implement CometChatMessageDelegate to be notified when a conversation is pinned or unpinned, so your list can reorder without a refetch. Both callbacks are optional and carry the full updated Conversation. They live on the message delegate rather than a separate conversation delegate, so the delegate you already register for message events receives them.
Register the delegate as you would for any message event — see Real-time Delegates and Listeners. To stop listening, call CometChat.removeMessageListener(_:) with the same listener ID. Delivery of these events activates once server-side real-time delivery for conversation-pin events is rolled out. Until then, update your list from the Conversation returned to pinConversation / unpinConversation on the acting device; the user’s other devices pick up the change on their next conversations fetch.

Pin Limit

A user can pin a capped number of conversations, configurable per app — see Properties and Constraints for the current value. System pins have their own separate cap and do not consume a user’s allowance. The iOS SDK exposes no getter for the cap. When the limit is breached, the SDK surfaces ERR_PINNED_CONVERSATIONS_LIMIT_EXCEEDED through onError, and the applicable limit is carried in the exception’s errorParams when the server includes it. Read it from there rather than hard-coding a number, and show generic copy when it is absent:
errorParams is [String: Any]? and is therefore not exposed to Objective-C. It is nil when the server sent no structured details, so always unwrap it.The conversation pin cap and the message pin cap are separate quotas with different values, and both are server-owned and tenant-overridable. Never assume one from the other.

Error Handling

Rejected locally by the SDK, before any network call: Returned by the server: If the server’s response cannot be read as a conversation, the SDK reports ERROR_UNSUCCESS_CONVERSATION_PIN or ERROR_UNSUCCESS_CONVERSATION_UNPIN.

Feature Availability

Check whether the Pin Conversation 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. It returns false until the app settings have been fetched, so UI gated on it stays hidden rather than offering an action the server would refuse.
Unlike the two message-level flags, this one is not seeded anywhere and is off by default — treat a false as the normal case for a new app, not as an error.

Next Steps

Pin & Save Messages

Pin a message for everyone, or save it privately

Retrieve Conversations

Every filter the conversations list supports

All Real Time Delegates

Every delegate the SDK exposes, in one place

Conversations UI Component

The UI Kit’s built-in pin swipe action