Skip to main content
Offline support keeps the logged-in user’s messages in a local database on the device. Turn encryption on to store that database encrypted at rest using SQLCipher. Encryption is opt-in and off by default; nothing changes until you set encryption: true. The minimum SDK version is 4.2.0.
Encryption covers the message database only. Downloaded media files (photos, voice notes, documents) stay as ordinary unencrypted files on disk, because their local paths are handed to image and video loaders. See What gets encrypted. This is not end-to-end encryption: CometChat’s servers still see message content.

Prepare your app

The SDK does not bundle the cipher engine or a key store, so apps that do not use encryption pay nothing for them. If you enable encryption you must provide both, on your side.
1

Compile SQLCipher into your app

The local database is provided by @op-engineering/op-sqlite. Add its SQLCipher flag to your app’s package.json and rebuild the native project:
package.json
2

Provide a secure key store

Install react-native-keychain; the SDK detects it automatically. Alternatively, supply your own store with CometChat.setOfflineKeyVault(vault) before init. A vault implements get(service), set(service, hexKey), delete(service) and kind(), where kind() reports "KEYSTORE", "SOFTWARE", or "NONE". Pass null to return to auto-detection.
If either is missing, the cache cannot run encrypted. What happens then is decided by encryptionFailureBehavior — by default the session runs online-only (no local cache). The SDK never creates a database that is labelled encrypted but is not.

Turn on encryption

Set encryption: true on the OfflineConfig you pass to the SDK during initialization (see Enable Offline Support). Like the other options, it is read once at init and fixed for the session.

Choose what happens when encryption cannot run

encryptionFailureBehavior decides what the cache does when encryption cannot be applied at all on this build or device — for example SQLCipher is not compiled into the app, or there is no secure key store. It governs only that case: a transient failure still retries without writing plaintext, 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 on disk 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.

Key storage

You do not generate or manage the encryption key. The SDK generates a random 32-byte key, one per app ID and logged-in user (UID), and keeps it in the platform keychain through react-native-keychain, or in the vault you supplied. The key never leaves the device and is never returned by any API. If the key is lost or the stored database no longer matches it, the cache resets and rebuilds — see Cache resets.

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, and never returns the key or any part of it.
The two most useful support signals are enabled === true with cipherAvailable === false (SQLCipher is not compiled into the app — add the op-sqlite flag and rebuild) and enabled === true with keyStorage === "NONE" (no secure key store — install react-native-keychain or set a vault).

What gets encrypted

Media bytes live outside the database because Attachment.getLocalPath() is public API and those paths are passed straight to media loaders. “Encrypted at rest” here always means the message database, never the media cache.

Cache resets on key loss

If the key can no longer decrypt the stored database, 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 database, so they cannot be counted or reported one by one: pendingMessagesLost is -1 (CometChat.OFFLINE_PENDING_COUNT_UNKNOWN). When the reset is ENCRYPTION_CHANGED instead, each queued message fails with reason DISCARDED and pendingMessagesLost is the exact count, unless the old database could not be read. 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, which also discards any queued messages and the cached media). See Stay in Sync for the full cache-reset flow and the complete list of reasons, and the API Reference for every field and enum.