Skip to main content
Offline support keeps the logged-in user’s messages in a local store on the device. Turn encryption on to store that content encrypted at rest. Encryption is opt-in and off by default; nothing changes until you set encryption: true.
This is not end-to-end encryption — the server still sees plaintext. It protects the on-device cache only. Cached media files are never encrypted, and in a browser some metadata stays readable so the cache can be queried. See What is and isn’t encrypted. Requires SDK 4.3.0 or later.

Requirements

Without a working cipher the cache cannot run encrypted. What happens then is decided by encryptionFailureBehavior — by default the session runs server-only (no local cache). The SDK never creates a cache that is labelled encrypted but is not.

Turn on encryption

Set encryption: true in the offline config you pass to setOfflineConfig (see Enable Offline Support).
Switching encryption on or off between launches rebuilds the cache in the new format and reports ENCRYPTION_CHANGED to the cache-reset listener; unsent messages are lost in that rebuild.

Choose what happens when encryption cannot run

encryptionFailureBehavior decides what the cache does when encryption cannot be applied at all on this runtime — for example an insecure origin in a browser (no crypto.subtle), or a plain better-sqlite3 instead of the cipher build in Electron. It governs only that case: a transient failure still retries, and a lost or wrong key self-heals by wiping and rebuilding the cache encrypted.
PLAINTEXT_FALLBACK means cached message content may be stored unencrypted whenever encryption cannot run. This availability-over-guarantee trade is wrong for compliance use — keep the default ONLINE_ONLY if cached content must never be written in the clear. Any value other than PLAINTEXT_FALLBACK is treated as ONLINE_ONLY.

Key storage

You do not supply or manage the encryption key. In a browser, the SDK generates a random per-user data key, wraps it with a non-extractable WebCrypto key, and keeps the wrapped key in the same IndexedDB as the data — so a browser clearing site data can never leave ciphertext without its key. In Electron the key is sealed by the OS through safeStorage. The key is never returned by any API. If it is lost or no longer opens the cache, the cache resets and rebuilds — see Cache resets.
In a browser the key lives in software next to the data (keyStorage: "SOFTWARE"). That protects against casual disk inspection and partial data copies, but not against code running in your page’s origin.

Check encryption status

CometChat.getOfflineEncryptionStatus() returns an object describing what encryption is actually doing — never what was merely requested. It is synchronous, safe to call at any time (even before login or with offline disabled), and never returns the key or any part of it.
The most useful support signal is enabled === true with cipherAvailable === false: encryption was switched on but could not run. In a browser that almost always means an insecure origin; in Electron, a missing better-sqlite3-multiple-ciphers cipher build. Check atRest to see whether a cache was opened at all.

What is and isn’t encrypted

On Electron the whole database is encrypted with SQLCipher; only the media files stay outside it.

Cache resets on key loss

If the key can no longer decrypt the stored cache, the SDK wipes the local cache and rebuilds it encrypted — it never silently falls back to plaintext for a cache that could be encrypted. Any unsent messages still queued in the outbox at that point are lost. They lived inside the unreadable store, so they usually cannot be counted: pendingMessagesLost is then -1 (CometChat.OFFLINE_PENDING_COUNT_UNKNOWN), not zero. Each lost message that could still be read fails with DISCARDED on onOutboxMessageFailed. Register an OfflineCacheResetListener to be told when this happens:
The encryption-related reasons are KEY_LOST, WRONG_KEY, CORRUPTED, ESCALATED, and ENCRYPTION_CHANGED (you turned encryption on or off between launches). See Stay in Sync for the full cache-reset flow, and the API Reference for every field and enum.