Product Updates

CometChat Offline Support

Keep chat working offline with CometChat SDKs: cached conversations, queued messages, reconnect sync, and optional cache encryption across five platforms.

Team CometChat • Nov 3, 2026

CometChat’s JavaScript, Android, iOS, Flutter, and React Native SDKs now keep chat working without a connection: conversations load from the device, and messages sent offline go out when the network returns.

A user opens your app on a train. The conversation list is a spinner, the message they just typed comes back with a red error, and they send it again to be safe. Nothing on your server broke; the network just left for a minute.

Fixing that yourself means a local database, a send queue that survives a restart, a sync job that knows what changed while the device was away, and a rule for wiping all of it when a different user logs in. That’s a lot of plumbing for something users only notice when it’s missing.

Offline support is now built into the CometChat Chat SDKs, behind one setting at init.

Why does this matter to me as a developer?

Users don’t experience “offline” as a network condition. They experience it as your app being broken. A blank chat list on one bar of signal reads as a bug, and a failed send reads as a lost message, even when the backend never had a problem.

Offline support moves that edge case into the SDK. The cache, the outbox, the reconnect sync, and the cleanup on logout follow the same model in all five SDKs. You decide how cached and pending states look; the SDK keeps them correct.

It’s off by default, and turning it on doesn’t change the calls you already make. You adopt the offline behavior one call at a time.

Key features and capabilities

Opens from the device. Conversation lists and message history load from a local cache first, then refresh from the server. On a dead connection, users see their chats instead of a spinner.

Send with no connection. A message sent offline goes into a durable outbox and is reported as pending, not failed. It survives an app restart (or a page reload on web) and sends when the connection returns.

Catches up on reconnect. When the connection returns, the SDK flushes the outbox and syncs the conversations and messages that changed while the device was away.

Media that stays viewable. Media received while online is cached on the device, up to 500 MB by default, so those photos and files still open offline.

Bounded, and cleaned up for you. By default the cache holds 100 conversations, 500 messages per conversation, and about 250 MB of content, evicting the oldest entries first; every limit is configurable. It’s kept per user: logging out, a session expiring, or a different user logging in deletes it, unsent messages included.

Optional encryption at rest. One more flag encrypts the local cache. In the JavaScript SDK that’s AES-256-GCM over cached content in the browser and SQLCipher in Electron, and if the runtime can’t encrypt, the default is to skip the local cache rather than write plaintext. It isn’t end-to-end encryption, and cached media files stay unencrypted.

Five CometChat SDKs, one model. Offline support ships in CometChat JavaScript SDK 4.3.0 or later (browser and Electron), Android SDK 5.1.0 or later, iOS SDK 4.2.0 or later, Flutter SDK 5.1.0 or later, and React Native Chat SDK 4.2.0 or later. Offline support in the CometChat UI Kits follows shortly.

What’s interesting about the tech

The opt-in happens twice: once at init, and again per call. Reads return cached results only when you pass the new fetch listener, and a send is queued only when you pass the new send listener (MessageSentListener in the JavaScript SDK). A send without one goes to the server exactly as before. That holds in all five SDKs, and it matters: a queued message is only safe if the screen that sent it can show “pending.” Queue sends behind a UI built for sent-or-failed, and users see an error for a message that’s going to arrive anyway, then send it again.

The JavaScript SDK carries that distinction onto the error path. Send with no connection and you get onMessagePending, then one onError with FAILED_TO_FETCH, and the returned Promise rejects. That error is a notice, not a failure: the message is still queued, and onMessageSent fires on reconnect. The Promise answers “was it sent just now?” while the listener tracks where the message is. To spot a real failure, read the status: PENDING sends on its own, FAILED waits for retryMessage(). A later send in the same conversation waits behind an unsent one, so order holds. Only new messages queue; edits, deletes, and reactions still need a connection.

Done right, the user never finds out the train went into a tunnel.

Reference links

Team CometChat

CometChat is a full-stack conversational platform used by teams from early-stage startups to global enterprises. We believe intelligent, scalable in-app communication shouldn't require starting from scratch. Turns out, a lot of builders agree.