diff --git a/docs.json b/docs.json
index 96952f214..3c478e277 100644
--- a/docs.json
+++ b/docs.json
@@ -457,6 +457,7 @@
"group": "Chat",
"pages": [
"ui-kit/react/core-features",
+ "ui-kit/react/offline-support",
"ui-kit/react/extensions",
"ui-kit/react/ai-features"
]
@@ -2583,6 +2584,7 @@
"group": "Chat",
"pages": [
"ui-kit/angular/core-features",
+ "ui-kit/angular/offline-support",
"ui-kit/angular/extensions",
"ui-kit/angular/ai-features"
]
@@ -3160,7 +3162,8 @@
"sdk/javascript/transient-messages",
"sdk/javascript/delivery-read-receipts",
"sdk/javascript/mentions",
- "sdk/javascript/reactions"
+ "sdk/javascript/reactions",
+ "sdk/javascript/offline-support"
]
},
"sdk/javascript/calling-overview",
@@ -10291,6 +10294,10 @@
"source": "/ui-kit/react/v7/core-features",
"destination": "/ui-kit/react/core-features"
},
+ {
+ "source": "/ui-kit/react/v7/offline-support",
+ "destination": "/ui-kit/react/offline-support"
+ },
{
"source": "/ui-kit/react/v7/event-system",
"destination": "/ui-kit/react/event-system"
diff --git a/sdk/javascript/llms-javascript-v4.mdx b/sdk/javascript/llms-javascript-v4.mdx
index 98f212703..57a5ca476 100644
--- a/sdk/javascript/llms-javascript-v4.mdx
+++ b/sdk/javascript/llms-javascript-v4.mdx
@@ -59,6 +59,7 @@ parameters, long-tail methods, group/user management, calling, or edge-case list
- [Delivery & Read Receipts](/sdk/javascript/delivery-read-receipts)
- [Mentions](/sdk/javascript/mentions)
- [Reactions](/sdk/javascript/reactions)
+- [Offline Support](/sdk/javascript/offline-support)
## Calling
- [Calling — Overview](/sdk/javascript/calling-overview)
diff --git a/sdk/javascript/offline-support.mdx b/sdk/javascript/offline-support.mdx
new file mode 100644
index 000000000..168c6fdcc
--- /dev/null
+++ b/sdk/javascript/offline-support.mdx
@@ -0,0 +1,727 @@
+---
+title: "Offline Support"
+sidebarTitle: "Offline Support"
+description: "Cache conversations and messages on the device, show them instantly, and queue messages sent without a connection with the CometChat JavaScript SDK."
+---
+
+
+
+| Field | Value |
+| --- | --- |
+| Package | `@cometchat/chat-sdk-javascript` |
+| Import | `import { CometChat } from "@cometchat/chat-sdk-javascript";` |
+| Enable | `new CometChat.AppSettingsBuilder().setOfflineConfig({ enabled: true, ... })` before `CometChat.init()` — offline support is **off by default** |
+| Key methods | `CometChat.isOfflineEnabled()` · `CometChat.getPendingMessages()` · `CometChat.retryMessage(message)` / `CometChat.retryAllFailedMessages()` · `CometChat.addSyncListener(name, listener)` / `CometChat.removeSyncListener(name)` · `CometChat.getOfflineEncryptionStatus()` · see [Other Offline Methods](#other-offline-methods) |
+| Two-phase reads | Pass a listener to `fetchPrevious()` / `fetchNext()` — e.g. `new CometChat.MessageFetchListener({ onCachedMessages, onServerMessages, onError })`; `CometChat.getConversation(with, type, new CometChat.SingleConversationFetchListener({...}))` |
+| Queued sends | Pass `new CometChat.MessageSentListener({ onMessagePending, onMessageSent, onError })` as the second argument of `sendMessage()` / `sendMediaMessage()` / `sendCustomMessage()` |
+| Offline send result | `onMessagePending` → `onError` (`FAILED_TO_FETCH`) and the Promise rejects, while the message stays queued → `onMessageSent` after reconnect. A send **without** a listener is not queued |
+| Failed sends | Status `FAILED`; never retried automatically. Retry with `CometChat.retryMessage(message)` or `CometChat.retryAllFailedMessages()` |
+| Storage | Browser IndexedDB (SQLite in a configured Electron app), one store per app ID and user, deleted on logout |
+| Constraints | Cached reads skip any request that uses a server-only filter such as `setSearchKeyword()`. Encryption is opt-in and covers the database only, not cached media |
+| Related | [Send a Message](/sdk/javascript/send-message) · [Receive a Message](/sdk/javascript/receive-message) · [Retrieve Conversations](/sdk/javascript/retrieve-conversations) · [Connection Status](/sdk/javascript/connection-status) |
+
+
+
+Offline support keeps a local copy of the logged-in user's conversations and messages on the device. Your app can render that copy the moment a screen opens — with or without a network — and the SDK replaces it with fresh server data as soon as it arrives. Messages sent while the device is offline are saved in a queue (the outbox) and sent automatically when the connection returns.
+
+Offline support is **opt-in**. Until you enable it, the SDK behaves exactly as it does today: nothing is stored on the device and every read goes to the server.
+
+{/* TODO(release): replace vX.Y.Z with the first JavaScript SDK release that ships offline support. */}
+Requires JavaScript SDK vX.Y.Z or later.
+
+## How It Works
+
+- **One local store per user.** The SDK keeps a separate store for each app ID and user, in the browser's IndexedDB. Logging out, or logging in as a different user, deletes the previous user's store.
+- **Cached, then server.** When you pass a listener to a read such as `fetchPrevious()`, the SDK first hands you what it has cached, then the server's result. Every server result is written back to the cache.
+- **Queued sends.** A message sent with a `MessageSentListener` is stored in the outbox first. If the device is offline, it stays queued and is sent automatically once the connection is back.
+- **Catch-up sync.** After a reconnect, the SDK sends queued messages, then refreshes the cached conversations and messages so changes made while you were offline (new, edited and deleted messages) reach the cache.
+- **The server wins.** If the cached copy and the server copy of a message differ, the server copy is kept.
+
+## Enable Offline Support
+
+Pass an offline configuration to `setOfflineConfig()` on the `AppSettingsBuilder`, then initialize the SDK as usual. Always include `enabled: true`.
+
+
+
+ ```typescript
+ let appID: string = "APP_ID";
+ let region: string = "APP_REGION";
+
+ let appSetting: CometChat.AppSettings = new CometChat.AppSettingsBuilder()
+ .subscribePresenceForAllUsers()
+ .setRegion(region)
+ .setOfflineConfig({
+ enabled: true,
+ maxPendingMessages: 50,
+ mediaCaching: CometChat.MediaCachingMode.AUTO,
+ })
+ .build();
+
+ CometChat.init(appID, appSetting).then(
+ (initialized: boolean) => {
+ console.log("Initialization completed successfully", initialized);
+ },
+ (error: CometChat.CometChatException) => {
+ console.log("Initialization failed with error:", error);
+ }
+ );
+ ```
+
+
+ ```javascript
+ let appID = "APP_ID";
+ let region = "APP_REGION";
+
+ let appSetting = new CometChat.AppSettingsBuilder()
+ .subscribePresenceForAllUsers()
+ .setRegion(region)
+ .setOfflineConfig({
+ enabled: true,
+ maxPendingMessages: 50,
+ mediaCaching: CometChat.MediaCachingMode.AUTO,
+ })
+ .build();
+
+ CometChat.init(appID, appSetting).then(
+ () => {
+ console.log("Initialization completed successfully");
+ },
+ (error) => {
+ console.log("Initialization failed with error:", error);
+ }
+ );
+ ```
+
+
+
+The offline store opens when a user logs in (or an existing session is restored) and closes on logout.
+
+
+ Access the offline enums through the `CometChat` namespace — for example
+ `CometChat.MediaCachingMode.AUTO` and
+ `CometChat.PendingMessageOverflowPolicy.REJECT_NEWEST`.
+
+
+### Configuration Options
+
+Set `enabled: true` to turn offline support on. Every other option is optional, and anything you leave out uses its default. The count limits accept the range shown; a value outside it, including `0`, is treated as the maximum.
+
+| Option | Type | Default | Description |
+| --- | --- | --- | --- |
+| `enabled` | `boolean` | `false` | Set `enabled: true` to turn offline support on. Nothing is stored on the device unless offline support is on. |
+| `maxPendingMessages` | `number` | `50` | How many messages the outbox can hold. Range 1–100. |
+| `pendingQueueOverflowPolicy` | `CometChat.PendingMessageOverflowPolicy` | `REJECT_NEWEST` | What happens when the outbox is full: `REJECT_NEWEST` rejects the new send, `DROP_OLDEST` marks the oldest queued message as failed to make room. |
+| `autoSendPendingOnReconnect` | `boolean` | `true` | Sends queued messages automatically after a reconnect. When `false`, a queued message is sent only when you call `retryMessage()` for it or a new message is sent in the same conversation. It does not affect the catch-up sync. |
+| `mediaCaching` | `CometChat.MediaCachingMode` | `AUTO` | `AUTO` downloads attachments of fetched and received messages so they can be viewed offline. `OFF` caches the message and its attachment details but not the file itself. |
+| `maxMediaCacheSize` | `number` (bytes) | `524288000` (500 MB) | Space cached media may use. The least recently used files are removed first. `0` means no limit. |
+| `maxStorageSize` | `number` (bytes) | `262144000` (250 MB) | Space the cached conversations and messages may use. The oldest messages are removed first. `0` means no limit. |
+| `maxConversations` | `number` | `100` | How many conversations the cache keeps. The least recently used conversation is removed first, with its messages. Range 1–1000. |
+| `maxMessagesPerConversation` | `number` | `500` | How many of the latest messages the cache keeps for each conversation. Range 1–1000. |
+| `cacheDurationDays` | `number` (days) | `0` | Removes a cached conversation that has had no new message and hasn't been opened for this many days. `0` means no time limit. |
+| `maxSnapshotQueries` | `number` | `100` | How many different list requests — users, groups, members and the other [lists](#other-lists), each with its own filters — are kept for offline use. The least recently used is removed first. Range 1–1000. |
+| `snapshotTtlDays` | `number` (days) | `7` | How long a cached list request stays available offline. After that it returns nothing offline until it is loaded online again. `0` means no time limit. |
+| `encryption` | `boolean` | `false` | Encrypts the cached data at rest. See [Encrypt the Cache](#encrypt-the-cache). |
+| `encryptionFailureBehavior` | `string` | `"ONLINE_ONLY"` | Applies only when `encryption` is `true` and encryption can't run on the device. `"ONLINE_ONLY"` opens no cache and the app works online only. `"PLAINTEXT_FALLBACK"` opens an unencrypted cache so offline support keeps working. |
+
+Messages waiting in the outbox, including failed ones, are never removed by these limits.
+
+## Check Whether Offline Is Running
+
+`CometChat.isOfflineEnabled()` returns `true` only while offline support is actually running for the logged-in user: you enabled it, a user is logged in, and the local store is open. It returns `false` before login, after logout, and when CometChat has switched offline support off for your app. Read it each time you need it instead of storing the value.
+
+
+
+ ```typescript
+ let offlineRunning: boolean = CometChat.isOfflineEnabled();
+ ```
+
+
+ ```javascript
+ let offlineRunning = CometChat.isOfflineEnabled();
+ ```
+
+
+
+CometChat can turn offline support off for an app from the server. When that happens, the SDK stops using the local store, deletes the cached data and `isOfflineEnabled()` returns `false`. Your app keeps working online.
+
+## Read From the Cache, Then the Server
+
+Pass a fetch listener to a request's `fetchPrevious()` or `fetchNext()` to receive results in two steps:
+
+1. `onCached*` — what is stored on the device, delivered immediately. It can be an empty list.
+2. `onServer*` — the server's result, which also updates the cache. If the device is offline, or the request fails, `onError` is called instead.
+
+The call still returns a Promise that settles with the server result, so handle the outcome in one place. Without a listener, the request reads from the server only, exactly as before.
+
+### Messages
+
+
+
+ ```typescript
+ let UID: string = "UID";
+ let limit: number = 30;
+
+ let messagesRequest: CometChat.MessagesRequest =
+ new CometChat.MessagesRequestBuilder()
+ .setUID(UID)
+ .setLimit(limit)
+ .build();
+
+ messagesRequest
+ .fetchPrevious(
+ new CometChat.MessageFetchListener({
+ onCachedMessages: (messages: CometChat.BaseMessage[]) => {
+ // Render the cached page right away
+ },
+ onServerMessages: (messages: CometChat.BaseMessage[]) => {
+ // Replace it with the server's page
+ },
+ onError: (error: CometChat.CometChatException) => {
+ // Offline or failed — keep showing the cached page
+ },
+ })
+ )
+ .catch(() => {
+ // Already handled in onError
+ });
+ ```
+
+
+ ```javascript
+ let UID = "UID";
+ let limit = 30;
+
+ let messagesRequest = new CometChat.MessagesRequestBuilder()
+ .setUID(UID)
+ .setLimit(limit)
+ .build();
+
+ messagesRequest
+ .fetchPrevious(
+ new CometChat.MessageFetchListener({
+ onCachedMessages: (messages) => {
+ // Render the cached page right away
+ },
+ onServerMessages: (messages) => {
+ // Replace it with the server's page
+ },
+ onError: (error) => {
+ // Offline or failed — keep showing the cached page
+ },
+ })
+ )
+ .catch(() => {
+ // Already handled in onError
+ });
+ ```
+
+
+
+### Conversations
+
+
+
+ ```typescript
+ let conversationsRequest: CometChat.ConversationsRequest =
+ new CometChat.ConversationsRequestBuilder().setLimit(30).build();
+
+ conversationsRequest
+ .fetchNext(
+ new CometChat.ConversationFetchListener({
+ onCachedConversations: (conversations: CometChat.Conversation[]) => {
+ // Render the cached list
+ },
+ onServerConversations: (conversations: CometChat.Conversation[]) => {
+ // Replace it with the server's list
+ },
+ onError: (error: CometChat.CometChatException) => {
+ // Offline or failed
+ },
+ })
+ )
+ .catch(() => {});
+ ```
+
+
+ ```javascript
+ let conversationsRequest = new CometChat.ConversationsRequestBuilder()
+ .setLimit(30)
+ .build();
+
+ conversationsRequest
+ .fetchNext(
+ new CometChat.ConversationFetchListener({
+ onCachedConversations: (conversations) => {
+ // Render the cached list
+ },
+ onServerConversations: (conversations) => {
+ // Replace it with the server's list
+ },
+ onError: (error) => {
+ // Offline or failed
+ },
+ })
+ )
+ .catch(() => {});
+ ```
+
+
+
+### A Single Conversation
+
+`getConversation()` accepts a third argument. When the conversation is not cached, `onCachedConversation` is not called.
+
+
+
+ ```typescript
+ let conversationWith: string = "UID";
+ let conversationType: string = "user";
+
+ CometChat.getConversation(
+ conversationWith,
+ conversationType,
+ new CometChat.SingleConversationFetchListener({
+ onCachedConversation: (conversation: CometChat.Conversation) => {},
+ onServerConversation: (conversation: CometChat.Conversation) => {},
+ onError: (error: CometChat.CometChatException) => {},
+ })
+ ).catch(() => {});
+ ```
+
+
+ ```javascript
+ CometChat.getConversation(
+ "UID",
+ "user",
+ new CometChat.SingleConversationFetchListener({
+ onCachedConversation: (conversation) => {},
+ onServerConversation: (conversation) => {},
+ onError: (error) => {},
+ })
+ ).catch(() => {});
+ ```
+
+
+
+### Other Lists
+
+The same pattern works for these requests:
+
+| Request | Listener | Callbacks |
+| --- | --- | --- |
+| `UsersRequest`, `BlockedUsersRequest` | `CometChat.UserFetchListener` | `onCachedUsers` · `onServerUsers` · `onError` |
+| `GroupsRequest` | `CometChat.GroupFetchListener` | `onCachedGroups` · `onServerGroups` · `onError` |
+| `GroupMembersRequest` | `CometChat.GroupMemberFetchListener` | `onCachedGroupMembers` · `onServerGroupMembers` · `onError` |
+| `BannedMembersRequest` | `CometChat.BannedMemberFetchListener` | `onCachedBannedMembers` · `onServerBannedMembers` · `onError` |
+| `ReactionsRequest` | `CometChat.ReactionFetchListener` | `onCachedReactions` · `onServerReactions` · `onError` |
+| `NotificationFeedRequest` | `CometChat.NotificationFeedFetchListener` | `onCachedNotificationFeedItems` · `onServerNotificationFeedItems` · `onError` |
+
+These lists are served from the cache only for a request that was loaded online before with the same filters. A list that has never been loaded online has nothing to show offline.
+
+### When the Cache Is Skipped
+
+The cache only answers a request when it can apply every filter on the request correctly. If a request uses a filter that only the server can evaluate — for example `setSearchKeyword()` — `onCached*` is not called and only the server answers. The cache phase is also skipped while offline support is not running.
+
+## Send Messages While Offline
+
+Pass a `MessageSentListener` as the second argument to `sendMessage()`, `sendMediaMessage()` or `sendCustomMessage()`. The listener has three callbacks:
+
+| Callback | When it fires |
+| --- | --- |
+| `onMessagePending(message)` | The message is saved in the outbox. Show it in the UI as pending. |
+| `onMessageSent(message)` | The server accepted the message. Replace the pending copy with this one. |
+| `onError(error)` | The send failed, or the device is offline (see below). |
+
+
+
+ ```typescript
+ let receiverID: string = "UID";
+ let receiverType: string = CometChat.RECEIVER_TYPE.USER;
+ let textMessage: CometChat.TextMessage = new CometChat.TextMessage(
+ receiverID,
+ "Hello",
+ receiverType
+ );
+
+ CometChat.sendMessage(
+ textMessage,
+ new CometChat.MessageSentListener({
+ onMessagePending: (message: CometChat.BaseMessage) => {
+ // Show the message with a pending indicator
+ },
+ onMessageSent: (message: CometChat.BaseMessage) => {
+ // Swap the pending copy for the sent message
+ },
+ onError: (error: CometChat.CometChatException) => {
+ // Offline: the message is still queued and will be sent on reconnect
+ },
+ })
+ ).catch(() => {
+ // Already handled in the listener
+ });
+ ```
+
+
+ ```javascript
+ let receiverID = "UID";
+ let receiverType = CometChat.RECEIVER_TYPE.USER;
+ let textMessage = new CometChat.TextMessage(receiverID, "Hello", receiverType);
+
+ CometChat.sendMessage(
+ textMessage,
+ new CometChat.MessageSentListener({
+ onMessagePending: (message) => {
+ // Show the message with a pending indicator
+ },
+ onMessageSent: (message) => {
+ // Swap the pending copy for the sent message
+ },
+ onError: (error) => {
+ // Offline: the message is still queued and will be sent on reconnect
+ },
+ })
+ ).catch(() => {
+ // Already handled in the listener
+ });
+ ```
+
+
+
+What happens depends on the connection:
+
+- **Online:** `onMessagePending`, then `onMessageSent`. The Promise resolves with the sent message.
+- **Offline:** `onMessagePending`, then `onError` once with the code `FAILED_TO_FETCH`, and the Promise rejects. The message is **not** lost — it stays in the outbox and is sent after the connection returns, when `onMessageSent` fires. Do not resend it yourself, or the recipient receives it twice.
+- **Outbox full:** with the default `REJECT_NEWEST` policy, the new send fails with `onError` (code `QUEUE_FULL`), the Promise rejects and the message is not saved.
+- **Rejected later:** if a queued message can't be sent once the connection is back, it is marked as failed. While the page that sent it is still open, `onError` is called again with the reason. See [Failed Messages and Retry](#failed-messages-and-retry).
+
+
+ Only sends that pass a `MessageSentListener` are queued. A send without a
+ listener behaves exactly as before: while offline, its Promise rejects and
+ the message is not saved.
+
+
+Use `message.getLocalMessageId()` to match the pending message to the sent one. The SDK assigns this ID when the message is queued; it is separate from any `muid` you set.
+
+### Get Pending Messages
+
+`CometChat.getPendingMessages()` resolves with the messages that are still in the outbox, including failed ones. Pass a conversation ID (`message.getConversationId()`) to get only that conversation's messages. Use it to show queued messages again after a page reload.
+
+
+
+ ```typescript
+ CometChat.getPendingMessages().then((messages: CometChat.BaseMessage[]) => {
+ console.log("Messages waiting to be sent:", messages);
+ });
+ ```
+
+
+ ```javascript
+ CometChat.getPendingMessages().then((messages) => {
+ console.log("Messages waiting to be sent:", messages);
+ });
+ ```
+
+
+
+It resolves with an empty list while offline support is not running.
+
+### Failed Messages and Retry
+
+`message.getStatus()` on a message from the outbox returns one of these `CometChat.MessageStatus` values:
+
+| Status | Meaning |
+| --- | --- |
+| `PENDING` | Queued. It is sent automatically when the device is connected. |
+| `SENDING` | Being sent now. |
+| `FAILED` | It could not be sent. It stays in the outbox until you retry it. |
+
+A queued message becomes `FAILED` when:
+
+- the server rejects it — for example, the receiver can't be messaged, the request isn't allowed, or the rate limit is exceeded;
+- the request keeps failing without a response from the server — the SDK retries it in the background a few times with an increasing delay first;
+- it is dropped from a full outbox by the `DROP_OLDEST` policy.
+
+The SDK never retries a `FAILED` message on its own. Retry it from your UI, for example from a "tap to retry" action:
+
+| Method | Description |
+| --- | --- |
+| `CometChat.retryMessage(message: BaseMessage \| string, listener?: MessageSentListener): Promise` | Queues one message again. Pass the message, or its `getLocalMessageId()`. |
+| `CometChat.retryAllFailedMessages(listener?: MessageSentListener): Promise` | Queues again every message that failed without a server response. Messages the server rejected, and messages dropped by `DROP_OLDEST`, are skipped; retry those one at a time with `retryMessage()`. |
+
+
+
+ ```typescript
+ CometChat.getPendingMessages().then((messages: CometChat.BaseMessage[]) => {
+ messages
+ .filter((message) => message.getStatus() === CometChat.MessageStatus.FAILED)
+ .forEach((message) => {
+ CometChat.retryMessage(message);
+ });
+ });
+ ```
+
+
+ ```javascript
+ CometChat.getPendingMessages().then((messages) => {
+ messages
+ .filter((message) => message.getStatus() === CometChat.MessageStatus.FAILED)
+ .forEach((message) => {
+ CometChat.retryMessage(message);
+ });
+ });
+ ```
+
+
+
+A retried message is sent right away when the device is connected, and otherwise on the next reconnect. Read its status with `getPendingMessages()` to update your UI.
+
+## Listen for Sync Events
+
+After a reconnect, the SDK runs a catch-up sync in two phases: conversations, then messages. Register a `SyncListener` to know when each phase starts, finishes or fails — for example, to refresh a screen once the sync is complete.
+
+
+
+ ```typescript
+ let listenerID: string = "UNIQUE_LISTENER_ID";
+
+ CometChat.addSyncListener(
+ listenerID,
+ new CometChat.SyncListener({
+ onConversationSyncStarted: () => {},
+ onConversationSyncCompleted: () => {
+ // Re-fetch the conversation list
+ },
+ onConversationSyncError: (error: CometChat.CometChatException) => {},
+ onMessageSyncStarted: () => {},
+ onMessageSyncCompleted: () => {
+ // Re-fetch the open message list
+ },
+ onMessageSyncError: (error: CometChat.CometChatException) => {},
+ })
+ );
+
+ // Remove it when you no longer need it
+ CometChat.removeSyncListener(listenerID);
+ ```
+
+
+ ```javascript
+ let listenerID = "UNIQUE_LISTENER_ID";
+
+ CometChat.addSyncListener(
+ listenerID,
+ new CometChat.SyncListener({
+ onConversationSyncStarted: () => {},
+ onConversationSyncCompleted: () => {
+ // Re-fetch the conversation list
+ },
+ onConversationSyncError: (error) => {},
+ onMessageSyncStarted: () => {},
+ onMessageSyncCompleted: () => {
+ // Re-fetch the open message list
+ },
+ onMessageSyncError: (error) => {},
+ })
+ );
+
+ // Remove it when you no longer need it
+ CometChat.removeSyncListener(listenerID);
+ ```
+
+
+
+You can register a sync listener at any time, including before login. Registering the same ID again replaces the earlier listener.
+
+### Updates Picked Up by the Sync
+
+The catch-up sync also tells your existing `MessageListener` what changed while the device was offline. Messages that are new to the device arrive through `onMessageReceived` as usual (for example `onTextMessageReceived`). Edits, deletions and other changes to messages that were already cached arrive together in `onMessagesSynced`. Update the matching messages in your UI by ID instead of appending them.
+
+
+
+ ```typescript
+ CometChat.addMessageListener(
+ "UNIQUE_LISTENER_ID",
+ new CometChat.MessageListener({
+ onMessagesSynced: (messages: CometChat.BaseMessage[]) => {
+ // Replace each message in your list by messages[i].getId()
+ },
+ })
+ );
+ ```
+
+
+ ```javascript
+ CometChat.addMessageListener(
+ "UNIQUE_LISTENER_ID",
+ new CometChat.MessageListener({
+ onMessagesSynced: (messages) => {
+ // Replace each message in your list by messages[i].getId()
+ },
+ })
+ );
+ ```
+
+
+
+## Other Offline Methods
+
+| Method | Description |
+| --- | --- |
+| `CometChat.forceSyncNow(callback?: (error?: CometChatException) => void): void` | Starts a catch-up sync now. The callback is called with `null` when it completes, or with an error code: `ERROR_OFFLINE_SYNC_IN_PROGRESS`, `ERROR_OFFLINE_SYNC_COOLDOWN` (within 10 seconds of the previous forced sync; the error has `retryAfterMs`), `ERROR_OFFLINE_DISABLED` or `USER_NOT_LOGGED_IN`. It doesn't send queued messages. |
+| `CometChat.getSyncState(): string` | `"SYNCING"` while a catch-up sync runs, otherwise `"IDLE"`. |
+| `CometChat.getLastSyncTimestamp(): Promise` | When the last catch-up sync completed, in milliseconds, or `0` if none has. |
+| `CometChat.getCacheSize(): Promise` | Size of the local cache in bytes. `0` while offline support is not running. |
+| `CometChat.clearOfflineCache(): Promise` | Deletes the current user's cached data and cached media, **including queued and failed messages**, without a callback for them. You don't need it on logout; the SDK clears the store itself. |
+| `CometChat.downloadMedia(attachment, callback?: MediaCallbackListener): void` | Downloads and caches an attachment, for example when `mediaCaching` is `OFF`. The callback has `onSuccess`, `onProgress(percent)` and `onError`. |
+| `CometChat.getCachedMediaObjectURL(attachment): Promise` | A `blob:` URL for a cached attachment that you can use as an `
` or `