Known limitations 5.x
This page describes public SDK API parameters that are not applied — or are applied with restrictions — in the current version (5.x), along with behavioral notes that you should keep in mind when integrating. Parameters not listed here work as documented.
Parameters overridden by the server
The ChatConfig properties listed below are marked @Deprecated. They are applied at runtime as a fallback — only if no value arrived from the server for the corresponding setting. The pattern in code is: serverValue ?: clientValue — the server setting always wins.
For production, do not rely on client-side values: the server configuration can override them without an app update.
| Parameter | Behavior | Notes |
|---|---|---|
ChatConfig.keepWebSocketActive | Falls back to the client value if the server does not send keepSocketActive | Subject to standard Android background limitations (Doze, App Standby) — there is no specific WebSocket behavior change on Android 15 |
ChatConfig.keepSocketActiveDuringOperatorSession | Falls back to the client value | — |
ChatConfig.searchEnabled | Falls back to the client value; controls the visibility of UI history search | — |
ChatConfig.linkPreviewEnabled | Falls back to the client value; enables link previews (OpenGraph) | — |
ChatConfig.voiceRecordingEnabled | Falls back to the client value; controls the visibility of the voice recording button | — |
ChatConfig.autoScrollToLatest | Falls back to the client value; mapped to the server field scrollToLatest | Client and server field names differ |
ChatConfig.surveyCompletionDelay | Falls back to the client value; defaults to 3 s if neither client nor server provides a value | — |
ChatConfigCore.historyLoadingCount | The field is declared as val — it cannot be overridden via ChatConfig. Used as a fallback in the absence of a server setting | The value can only be changed by rebuilding ChatConfigCore entirely |
Fields with no effect in the current version
| Parameter | Behavior | Notes |
|---|---|---|
ChatFlow.fullScreenMode | Marked @Deprecated ("since targetSdk = 35, ChatCenterUI no longer uses this parameter — it is always true"), not read at runtime. Edge-to-edge mode is determined by Android's behavior in the integrating app at targetSdk = 35 and your Activity theme | Setting a value has no effect |
ChatTexts (entire class) | All fields are marked @Deprecated. To localize UI strings, override ecc_* keys in strings.xml | See Localization |
WebSocket disconnect behavior
Starting with version 5.21.0, the SDK supports automatic WebSocket reconnect. It is disabled by default and enabled via the isReconnectEnabled parameter in WSConfig — see Network config.
When isReconnectEnabled = false (the default), after a WebSocket disconnect the socket is closed, new messages are not sent or received, and queued messages remain in PENDING / FAILED status until the session is restored.
What to do on the app side:
- Subscribe to
ConnectivityManager.NetworkCallbackto track network restoration; - When the network is restored, re-call
chatCenterUI.authorize(user, auth). Add a guard on the app side against repeated calls with identical parameters — the SDK does not perform an early-return and re-establishes the internal connection on identical arguments; - Show an offline indicator to the user until the session is restored;
- Handle the disconnect via
ChatCenterUIListener.networkErrorReceived(error)— see Methods → Errors. This callback is not delivered on the main thread — see the recommended switching idiom and the full thread table in Delegates → Callback threads.
State restoration screen
If SDK screens (chat, attachment gallery, SDK dialogs) are opened by the system before the app has called init(...) / initAsync(...), the SDK protects the integration from crashes:
- a full-screen placeholder with the text "Restoring state…" (string
ecc_restoring_state) is shown overChatFragment; - the attachment gallery (
ImagesActivity) and SDK dialogs (BottomSheet,Dialog) close automatically.
This scenario occurs, for example, during system activity recreation (Activity recreation, low memory), when the user process was killed and Android restored the last screen before your Application.onCreate had a chance to initialize the SDK.
What to do on the app side:
- Call
init(...)/initAsync(...)as early as possible — inApplication.onCreate, not inActivity.onCreate. This minimizes the time the placeholder is shown. - If your launcher activity performs additional work before
init(...), consider switching to asynchronous initialization withinitAsync(...)so that the app's UI does not depend on heavy SDK operations. - The placeholder colors and text can be overridden — see Design system → Colors → State restoration screen and Localization.
SSL
allowUntrustedCertificates = true in a production buildThis parameter is intended only for development builds against a local test server. Setting it to true fully disables TLS validation and leaves the connection vulnerable to MITM. The flag's value does not depend on the build type — if you accidentally leave it enabled, it will take effect in release as well.
What to do before release:
- Explicitly set
SSLPinningConfig(allowUntrustedCertificates = false)in the production configuration; - Do not read the value from a remote-config / env source that could be flipped in production;
- Do not override the value via BuildType overrides in the release build.
See also: Network config and Troubleshooting.
Behavioral notes
Race condition on parallel ChatCenterUI calls
ChatCenterUI methods only from the main threadChatCenterUI methods (init(), authorize(), logout(), send(), etc.) must be called only from the main thread. Parallel calls from multiple threads are not supported and may lead to undesired effects — for example, duplicate push-token registration or desynchronization between the WebSocket session and the local state.
What to do on the app side:
- Call
ChatCenterUImethods only from the main thread; if you need to invoke them from a background thread, wrap the call withrunOnUiThread { ... }orHandler(Looper.getMainLooper()).post { ... }; - If your app has several entry points that may call
authorize(...)(e.g., a push handler and a splash screen), add your own guard / serialization on the app side; - Do not call
authorize(...)again "just in case" — with identical parameters, the SDK re-establishes the internal connection (see also the WebSocket disconnect behavior section).
ChatConfig.equals() is unstable across API levelsThe equals() implementation for ChatConfig only compares the notificationImportance field starting from Android 7.0 (API 24, Build.VERSION_CODES.N). On older APIs, two configs with different notificationImportance are considered equal; on API ≥ 24, they are not.
Symptom: ChatConfig instances cannot be reliably used as keys in HashMap/Set or compared via == in conditional logic, especially if your codebase's minimum API is below 24. Keep a single config instance and check identity with ===.
UnreadMessagesController is an enum singletonUnreadMessagesController is available as an INSTANCE-singleton. This simplifies controller access in production but complicates unit tests: you cannot substitute INSTANCE with a test double without reflection.
What to do on the app side: wrap UnreadMessagesController in your own interface/facade and inject that facade into the code that requires unit testing.
ChatAuthType.COOKIES — no reference exampleThe ChatAuthType enum class has a COOKIES value, but only HEADERS is documented publicly. COOKIES works but lacks examples and regression coverage; use it only after prior alignment with edna support.
ChatUpdateProcessor coroutine scopes
ChatUpdateProcessor bus may arrive on any threadIn ChatUpdateProcessor, every postX(...) method emits an event from a new CoroutineScope(Dispatchers.Unconfined) — therefore the collector may receive an event on the OkHttp WebSocket thread or any other arbitrary thread.
Do not use flowOn(Dispatchers.Main) — this operator changes the context of the upstream emitter, not your collector, and in this case will not switch anything.
Correct alternatives:
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
chatUpdateProcessor.newMessageFlow.collect { item ->
withContext(Dispatchers.Main) {
// safe UI calls
}
}
}
}
lifecycleScope starts on Dispatchers.Main.immediate, so without withContext you'll already be on main if your collect block does not perform background work.
Which callbacks on which thread. unreadMessageCountChanged, exceptionReceived, urlClicked are delivered on the main thread. networkErrorReceived is always delivered from a background thread. A thread summary and the recommended switching idiom are in the canonical section Delegates → Callback threads.
For more on subscribing to this bus, see Methods → Delegates → Advanced scenarios.
Related sections
- Design system: overview — customization levels.
- Troubleshooting — diagnostics and production checklist.
- Network config — allowed combinations of SSL parameters.
- Errors (methods) — handling
networkErrorReceivedand retry strategy. - Accessibility — a separate section on a11y limitations.
- Localization — migration from
ChatTextstoecc_*keys instrings.xml. - Themes —
ChatThemeand three constructor forms. - Components —
ChatComponents, whereChatTextswas historically passed as thetextparameter. - Flows —
ChatFlow.fullScreenModelives here.