In-App Messaging Guide
This guide will show you how to integrate the Webex Connect In-App Messaging capability into your Android application.
This guide will show you how to integrate the Webex Connect In-App Messaging capability into your Android application.
Please ensure you have integrated the In-App Messaging Module by following the Quick Start Guide.
Note
Deprecation of Legacy SDKs
With the release of our new Modular SDKs for Android and iOS, we advise all users to transition to these enhanced SDKs as soon as possible. The Legacy SDKs version 2.x.x will be deprecated on 20th August 2025, after which they will no longer receive support or updates.
To ensure you benefit from the latest features and improvements, please begin the migration process at your earliest convenience. For guidance, refer to our migration documentation or reach out to our support team for assistance.
Overview of In-App Messaging
In-App Messaging allows bi-directional communication between the Webex Connect platform and your mobile application. Messaging is thread-based, meaning all messages are associated with a specific thread. A thread can be viewed as a chronological sequence of messages presented as a conversation. An end user can participate in one or more threads.
Types of Threads
Webex Connect supports two types of threads:
Conversation Threads: These threads are used for bi-directional communication, making them well-suited for chat experiences.
Announcement Threads: These threads are uni-directional, from the platform to the mobile app, and are ideal for service messages, alerts, and offers.
Messages are delivered via real time connection between the SDK and the Webex Connect message broker. Messages that are published when the real time connection is not active, will be held at the broker for a maximum of 24 hours, and will be delivered once a connection has been established. Messages that are not delivered within the 24 hour period will be removed from the broker and will not be delivered via the real time connection, although can still be retrieved from the Server-Side Inbox (see below).
Our Server-Side Inbox feature persists threads and messages within the Webex Connect platform for later retrieval via API. Data is persisted for a period of 30 days, although this can be adjusted upon request via your account manager. The maximum data retention period is 1 year.
Note
The Server Side Inbox feature must be enabled within your app asset configuration. If the feature is not enabled, any messages that are not delivered via real-time connection within 24 hours of publication, will be lost.
Below are the steps, you need to complete to enable In-App Messaging in your app.
a. Establishing a connection
b. Listening for connection status events
c. Receiving messages
d. Creating threads
e. Publishing messages
f. Closing the connection
a. Establishing a connection
In App Messaging uses its own dedicated connection, therefore you must establish the connection with the Webex Connect platform before messages can be received. Connection is established by invoking the connect method as shown below.
try {
InAppMessaging.instance.connect()
}catch (e: Exception) {
//Handle exception
}
try {
InAppMessaging.getInstance().connect();
} catch (WebexConnectException e) {
//Handle exception
}
Note
You only need to call the
connectmethod once, after which the SDK will manage the connection for you, even between app restarts. The SDK will stop managing the connection if thedisconnectmethod is called.
b. Listening for connection status events
The SDK exposes the current status of the messaging connection via the connectionStatus enumeration.
As connection status changes the SDK raises events to notify the change to your application code. To receive these events in your application, implement and register a ConnectionStatusListener.
InAppMessaging.instance.registerConnectionStatusListener { connectionStatus ->
//Handle the connection status change
}
InAppMessaging.getInstance().registerConnectionStatusListener(connectionStatus ->
{
//Handle the connection status change
return Unit.INSTANCE;
});
Note
Mobile data connections can be unreliable, therefore it is normal for disconnects to occur. In case of a disconnection the SDK will automatically re-establish the connection for you.
c. Receiving messages
As messages are received by the SDK they are emitted via listeners. Register a listener by calling the registerMessageListner method.
InAppMessaging.instance.registerMessagingListener { inAppMessage ->
// Handle the message
}
InAppMessaging.getInstance().registerMessagingListener(inAppMessage -> {
// Handle the message
return Unit.INSTANCE;
});
d. Creating threads
To create a new thread, instantiate an InAppThread object, set the required data fields, and invoke the createThread method.
val thread = InAppThread()
thread.title = "title"
thread.category = "category"
InAppMessaging.instance.createThread(thread) { inAppThread: InAppThread?, exception: WebexConnectException? ->
if (exception == null) {
//Handle success
} else {
//Handle exception
}
}
InAppThread thread = new InAppThread();
thread.setTitle("title");
thread.setCategory("category");
InAppMessaging.getInstance().createThread(thread, (inAppThread, exception) - > {
if (exception == null) {
//Handle success
} else {
//Handle exception
}
return Unit.INSTANCE;
});
e. Publishing messages
To publish a message, create an instance of InAppMessage, set the required data fields, and call the publishMessage method. Messages must be assigned a valid InAppThread instance, which is obtainable by creating a new thread, fetching existing threads, or from an existing InAppMessage.
val message = InAppMessage()
message.message = "Test message"
message.thread = yourThreadObj
InAppMessaging.instance.publishMessage(message) { publishedMessage: InAppMessage?, exception: WebexConnectException? ->
if (exception != null) {
//Handle exception
} else {
//Handle success
}
}
InAppMessage message = new InAppMessage();
message.setMessage("Test message");
message.setThread(yourThreadObj);
InAppMessaging.getInstance().publishMessage(message, (publishedMessage, exception) - > {
if (exception != null) {
//Handle exception
} else {
//Handle success
}
return Unit.INSTANCE;
});
f. Closing the connection
The In-App Messaging module will normally manage the messaging connection for you, automatically connecting and disconnecting as your app transitions between background and foreground states. However, if you wish to disconnect and prevent the In-App Messaging module from re-establishing the connection, you may call the disconnect method.
try {
InAppMessaging.instance.disconnect()
} catch (e: Exception) {
// Handle exception
}
try {
InAppMessaging.getInstance().disconnect();
} catch (WebexConnectException e) {
// Handle exception
}
g. Deleting Messages
Add as: g. Deleting messages
API: section 2.1.1 deleteMessage
Use deleteMessage to delete a previously sent in-app message. The SDK exposes two overloads: pass either the full InAppMessage instance, which is recommended, or the message's transactionId.
Kotlin
InAppMessaging.instance.deleteMessage(message) { deletedMessage: InAppMessage, exception: WebexConnectException? ->
if (exception != null) {
// Handle exception
} else {
// Message deleted successfully - update your UI
}
}
Java
InAppMessaging.getInstance().deleteMessage(message, (deletedMessage, exception) -> {
if (exception != null) {
// Handle exception
} else {
// Message deleted successfully - update your UI
}
return Unit.INSTANCE;
});
Note: Deletion is server-authoritative. The deleted message will be removed from the server-side inbox and propagated to other connected clients of the same user.
h. Contact Center (CC) integration
h. Contact Center (CC) integrationAPI: section 2.3 InAppMessage - New Fields
For tenants integrated with Webex Contact Center (CC), every in-app message is correlated with a CC-side identifier in addition to the existing Connect transactionId. The new ccTransactionId field on InAppMessage is populated only for CC-enabled tenants.
| Field | Type | Description |
|---|---|---|
transactionId | String? | Existing identifier for the message on the Webex Connect platform. |
ccTransactionId | String? | New Contact Center-scoped identifier. Populated only for CC tenants; null for non-CC tenants. The two IDs are correlated by the server. |
Kotlin
InAppMessaging.instance.registerMessagingListener { message ->
val connectId = message.transactionId
val ccId = message.ccTransactionId
if (ccId != null) {
// CC tenant - use ccTransactionId when reporting back to CC systems
}
}
Looking up a message by either ID
The local MessageStore will resolve a lookup by either transactionId or ccTransactionId, so callers integrating with CC backends can pass whichever identifier is available.
val message = messageStore.loadMessage(idFromCc) // resolves via transactionId or ccTransactionId
Note: CC tenants should persist
ccTransactionIdalongsidetransactionIdto enable cross-system correlation, such as agent desktop or CC reporting.
i. Handling redacted messages
i. Handling redacted messagesAPI: section 2.3 InAppMessage - New Fields
To support privacy, compliance, and Data Subject Request (DSR) flows, the server may redact previously delivered messages. When a message has been redacted, its content is stripped server-side and the new isRedacted flag is set to true.
| Field | Type | Description |
|---|---|---|
isRedacted | Boolean | true when the server has stripped the original message content for privacy, compliance, or DSR. UI must render a redacted placeholder instead of the original body. |
Kotlin example - rendering
val displayText = if (message.isRedacted) {
getString(R.string.message_redacted_placeholder) // e.g. "This message has been removed"
} else {
message.message
}
Important: Do not display the original
messagecontent whenisRedacted == true. The body may still be present locally from a prior sync but is no longer authorized for display.
j. Showing a thread preview
j. Showing a thread previewAPI: section 2.4 InAppThread - New Fields
InAppThread now exposes the most recent message and a short preview string, enabling chat-list UIs without an extra fetchMessages round trip.
| Field | Type | Description |
|---|---|---|
lastMessage | InAppMessage? | The most recent message in the thread, or null if not available. |
lastMessagePreview | String? | A preview string for the most recent message, server-generated and safe for direct display in a list cell, or null. |
Kotlin - typical inbox binding
InAppMessaging.instance.fetchThreads(beforeDate = Date(), limit = 50, callback = { threads, hasMore, exception ->
if (exception == null) {
threads.forEach { thread ->
val preview = thread.lastMessagePreview ?: thread.lastMessage?.message.orEmpty()
// bind preview to the thread row
}
}
})
k. Business hours and availability
k. Business hours and availabilityAPIs: section 2.1.2 fetchBusinessHoursDetail, section 2.1.3 fetchBusinessAvailability, and section 2.2 businesshours package.
For Contact Center and customer-support style apps, the SDK can surface the tenant's configured business hours and tell you whether the tenant is currently available. Use this to enable or disable the composer, show an "out of hours" banner, or route the user to an alternative channel.
Fetch The Full Schedule
fetchBusinessHoursDetail returns the weekly schedule along with any linked override windows and holiday lists.
Kotlin
InAppMessaging.instance.fetchBusinessHoursDetail { detail: BusinessHoursDetail?, exception: WebexConnectException? ->
if (exception != null) {
// Handle exception
return@fetchBusinessHoursDetail
}
detail?.businessHours?.workingHours?.forEach { shift ->
// shift.days, shift.startTime, shift.endTime
}
detail?.holidaysDetail?.holidays?.forEach { holiday ->
// holiday.name, holiday.startDate, holiday.endDate
}
detail?.overridesDetail?.overrides?.forEach { override ->
// override.name, override.startDateTime, override.endDateTime
}
}
Check Current Availability
fetchBusinessAvailability returns the slot the current time resolves to, along with details of the active slot.
Kotlin
InAppMessaging.instance.fetchBusinessAvailability { availability: BusinessAvailability?, exception: WebexConnectException? ->
if (exception != null) {
// Handle exception
return@fetchBusinessAvailability
}
when (availability?.type) {
BusinessAvailabilityType.WORKING_HOURS -> {
// Open - enable composer; availability.activeWorkingHour is populated
}
BusinessAvailabilityType.HOLIDAY -> {
// Closed for a holiday - availability.activeHoliday is populated
}
BusinessAvailabilityType.OVERRIDE -> {
// Special override window - availability.activeOverride is populated
}
BusinessAvailabilityType.NO_MATCH -> {
// Outside any configured slot - show "out of hours" message
}
BusinessAvailabilityType.ERROR, null -> {
// Could not be evaluated - fail open or fail closed per your policy
}
}
}
Note: Both APIs are network calls. Cache the result for a short window, for example a few minutes, instead of calling on every UI render. Business hours are evaluated server-side against the tenant timezone, so clients do not need to perform timezone math locally.
l. File attachment changes
l. File attachment changesAPI: section 2.5 InAppFileAttachment - New Fields and section 2.7 FileUploadCallback - Parameter Rename.
InAppFileAttachment now carries the original filename and signals when an attachment is no longer retrievable.
| Field | Type | Description |
|---|---|---|
fileName | String? | The original filename with extension, useful for download or save UI. |
isDropped | Boolean | true when the attachment is no longer retrievable from the server, for example retention expired. UI should render a "file unavailable" state and skip download attempts. |
Kotlin - rendering an attachment row
val attachment = message.attachment as? InAppFileAttachment ?: return
when {
attachment.isDropped -> showUnavailable(attachment.fileName ?: getString(R.string.unknown_file))
else -> showDownloadable(attachment.fileName, attachment.url)
}
Upload Callback Parameter Rename
FileUploadCallback.onFileUploadComplete has had its second parameter renamed from mediaId to mediaReference. The value is unchanged in semantics: it is the media ID or URL of the uploaded file, depending on the asset configuration. Update existing callers:
mediaFileManager.uploadFile(file, object : FileUploadCallback {
override fun onFileUploadComplete(file: File, mediaReference: String?, exception: WebexConnectException?) {
// Use mediaReference where you previously used mediaId
}
override fun onFileUploadProgress(file: File, progress: Int) {
/* ... */
}
})
Note: This is a parameter name change only. There is no runtime behavior change. Existing apps recompile cleanly; the rename clarifies that the value may be either an ID or a URL.
With this you have successfully integrated the In-App Messaging module within your app.
Updated about 1 month ago
