Skip to main content
When the device comes back online, the SDK runs a catch-up sync: it refreshes the conversation list, then replays everything that changed in your messages since the last sync, and merges the results into the local cache. This page covers how to observe that sync, trigger one on demand, and manage the cache it maintains.
Everything on this page is a no-op unless offline support is active for the logged-in user (CometChat.isOfflineEnabled() is true). See Enable Offline Support.

How catch-up works

A sync runs automatically whenever the connection settles, including the first connect after login or launch. It never runs on a brief connect-then-drop flap, and overlapping triggers coalesce: at most one follow-up sweep is queued behind the running one. It proceeds in two phases, in order:
  1. Conversation phase — the conversation list is fetched as one fresh page. A conversation-list UI can blind-replace its list with the result.
  2. Message phase — the SDK replays the message changelog from the last sync point. New messages and updates to already-cached messages are merged into the cache.
The sync is incremental and safe to repeat: it only moves forward from the last successful point, and a failed or interrupted phase simply resumes on the next reconnect. The conversation refresh does remove conversations you are no longer part of, along with their cached messages, media, and any still-queued messages for them (which fail with reason discarded). A first-ever sync (cold start) seeds its starting point from the newest conversation and fetches no message history — older history is reached by scrolling online.

Listen for sync progress

Register a SyncListener to observe the lifecycle of every automatic and manual sync. Each phase fires started, then exactly one of completed / error, all on the main isolate. Override only the callbacks you need.
The two phases are independent — a conversation-phase error does not stop the message phase. A phase error is informational: the cache is never left in a wrong state and the sweep resumes automatically. The SyncListener is self-sufficient: onMessageSyncCompleted carries the swept messages, including action and call messages that the MessageListener does not deliver, so you can use it without a MessageListener. onMessageSyncCompleted reports the outcome: Remove the listener with CometChat.removeSyncListener("SYNC_LISTENER").

Receiving synced messages

If you already use a MessageListener, synced messages still arrive there, so you usually do not need a SyncListener to keep your chat up to date:
  • Genuinely new messages arrive one-by-one on the typed callbacks (onTextMessageReceived, onMediaMessageReceived, onCustomMessageReceived, …), each tagged with source 'SYNC'.
  • Updates to already-cached messages arrive together on onMessagesSynced(List<BaseMessage>).
On reconnect, queued messages are sent first, then the sync runs. forceSyncNow runs only the sync; it does not send queued messages (use retryMessage or retryAllFailedMessages for those). A message deleted on the server reaches you as an update on onMessagesSynced, not as a removal.

Check sync state

Poll the current sync state and the time of the last completed sync at any time.
getSyncState() returns SyncState.syncing while a sweep is in flight, otherwise SyncState.idle (also when offline support is disabled). getLastSyncTimestamp() returns the time of the last completed message-sync as a device-clock epoch value in milliseconds, and null if the cache has never synced. It is informational — a value to show in a UI, not a cursor the sync depends on.

Trigger a manual sync

Call forceSyncNow to run a catch-up immediately — for example behind a pull-to-refresh. It routes through the same throttle as the automatic sync, so it will not start a second overlapping sweep or hammer the backend. Pass a ForceSyncListener to learn whether the request was accepted; the sync’s actual progress and outcome still arrive on your registered SyncListener.
If you do not need the acceptance result, call CometChat.forceSyncNow() with no callback; a rejected request is silently dropped.

When the cache resets

In rare cases the SDK cannot keep the existing cache — for example the encryption key became unrecoverable, or the database file is corrupt. When this happens it rebuilds the cache from scratch and notifies an OfflineCacheResetListener. Any un-sent messages that were queued are lost in the rebuild; pendingMessagesLost reports how many — or null when it cannot be known.
Remove the listener with CometChat.removeOfflineCacheResetListener("RESET_LISTENER"). See Encrypt the Cache for the encryption-related reasons.

Manage the cache

Read the current cache size, or clear the cache entirely.
getCacheSize() returns the total cache size in bytes (local database plus the media byte store) as a single figure, or 0 when offline support is disabled or nobody is logged in.
clearOfflineCache() is destructive and irreversible. It empties the entire per-user cache — cached messages, conversations, media bytes and the un-sent outbox. Each still-queued pending / sending message fails with reason discarded; messages that had already failed are removed without a further callback. It is a no-op unless offline support is active.
You never need to clear the cache on logout — the SDK does it for you. The cache is stored per user: it survives app restarts and a token refresh for the same logged-in user, and is wiped automatically on logout, when the server rejects the auth token, or when a different user or app ID is used. See Offline Support.