Skip to main content

Goal

By the end of this guide you will have a chat screen where users can pin a message so it’s highlighted for everyone in the conversation, open a screen of all pinned messages, and save a message privately to their own list — with a dedicated “Saved” screen to review saves across every conversation. Pin and save are two separate concepts:

Prerequisites

  • Completed the Integration Guide
  • An existing chat screen using CometChatMessageHeader, CometChatMessageList, and CometChatMessageComposer
  • Pin messages and Save messages enabled for your app through the features.ux.messages.pinned.enabled and features.ux.messages.saved.enabled app settings. See Core Features → Pin & Save.
The pin/unpin and save/unsave options only appear in the message options when the corresponding feature is enabled for your app. The UI Kit reads that setting at login and re-reads it on every reconnection, so no extra wiring is needed to show or hide the options.

Step 1: The Message Options

Once the features are enabled, CometChatMessageList automatically adds Pin, Unpin, Save, and Unsave to the message options — no props required. You only need the hide* props if you want to remove one: File: Messages.tsx
The Pin/Unpin option is shown to every member — the UI Kit does not gate it by role. Permission is enforced by the server: if a member isn’t allowed to pin or unpin in that conversation, the action is rejected and the UI Kit shows a permission toast. Saving is per-user and always available.
The options are hidden on messages the server would refuse anyway — an unsent message with no ID yet, a deleted message, or one moderation has disapproved. A message still pending a moderation verdict keeps both options: the kit offers them and lets the server decide, so a genuinely early tap earns a real error toast instead of a control that silently disappears and comes back.

Step 2: Open the Pinned Messages Screen

CometChatMessageHeader can add a Pinned Messages item to its ⋮ overflow menu. Set showPinnedMessagesButton and wire onPinnedMessagesPress — the entry only appears when both are given — to navigate to CometChatPinnedMessages, scoped to the same user/group. File: Messages.tsx
File: PinnedMessages.tsx
CometChatPinnedMessages is per conversation — it takes the same user or group the chat screen was opened with, and lists that conversation’s pinned messages newest-pin first.
The Pinned Messages screen listing one conversation's pinned messages as full bubbles, each with a pin glyph beside its timestamp.

Step 3: Add a “Saved” Screen

CometChatSavedMessages is user-level, not per conversation — it lists everything the logged-in user has saved, across every chat. There is no built-in entry point, so open it from your own navigation: a menu item, a profile screen, or a tab.
The Saved Messages screen listing saved messages from across every conversation, each row showing its source conversation and a one-line preview.
File: SavedMessages.tsx
Each row shows which conversation the message came from, so a saved message is never orphaned from its context. source carries that conversation as receiverType ("user" or "group") and receiverId, plus name, label and an optional avatar — see the component reference.

Step 4: Pinned & Saved Indicators

No wiring needed. CometChatMessageList renders a pin glyph and a filled bookmark in the message’s meta row, beside the timestamp, and keeps them in sync in real time:
  • Pin is conversation-wide, so every participant sees the indicator appear and disappear as the message is pinned or unpinned.
  • Save is private, so the indicator appears only for the user who saved it — and syncs to that user’s other devices.

Helpers

For your own UI — a custom bubble, a badge, a screen that needs to know before it renders — the kit exports the same helpers it uses itself:
You do not need refreshPinSaveFeatures() in normal use. The UI Kit resolves the flags at login and re-reads them on every reconnect; call it only after changing the setting in the Dashboard and wanting a running app to pick it up without a reconnect. Before the first resolution completes it returns everything false.

Step 5: App Settings and Limits

Each feature is switched on per app, and each carries a cap. Both are configured as app settings in the dashboard: When a user hits a cap the action is rejected and the UI Kit shows a toast — you do not need to handle the error yourself. The kit resolves the number from the app settings it caches at login, falling back to errorParams.limit when the rejection happens to carry one.
The toast does not always name a number. The server documents these caps as tenant-overridable settings and does not promise them on the error payload, so when neither source has a value the kit deliberately shows copy without a figure rather than printing a guess. Do not write UI that depends on a number being present.

Complete Example

File: Messages.tsx
goToMessageId is what makes the jump actually happen: CometChatMessageList fetches the page around that ID and scrolls to it, so tapping a pinned or saved row lands on the message in its original conversation.

Next Steps