Android
The Kavchat Android library adds the scripted support bot to your app, with Jetpack Compose components and an activity for apps built with Views. Answers are predictable and keep working offline from the last published release. Requires Android 6.0 (API 23) or later.
There are two artifacts: kavchat-engine, a pure Kotlin/JVM port of the conversation engine with no Android or third-party dependencies, and kavchat, with networking (HttpURLConnection), the on-device cache (SharedPreferences), the Compose KavchatChat and KavchatLauncher, and KavchatActivity.
Install
// settings.gradle.kts
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven("https://jitpack.io")
}
}
// app/build.gradle.kts
dependencies {
implementation("com.kavchat:kavchat-android:0.0.11")
}The library is served by JitPack, so add its repository once, next to google() and mavenCentral(). The SDK is open source under the MIT license: bitbucket.org/maxsave/kavchat-android.
The library declares the INTERNET permission and KavchatActivity in its manifest. There is nothing to add by hand.
Setup
Call configure once, in Application.onCreate:
class App : Application() {
override fun onCreate() {
super.onCreate()
Kavchat.configure(this, publicKey = "pk_live_...")
// Optional: Kavchat.configure(this, "pk_live_...", apiBase = "https://api.kavchat.com", locale = "he")
}
}The public key is safe to ship in the app. Never ship the secret key (sk_live_...).
Compose
A floating button in the corner set in the dashboard, which opens the chat full screen:
KavchatOverlay(Modifier.fillMaxSize()) {
AppContent()
}Or place the button yourself, or embed the chat in your own screen:
KavchatLauncher() // com.kavchat.ui.KavchatLauncher
KavchatChat(Modifier.fillMaxSize()) // full chat, no close button
KavchatChat(Modifier.fillMaxSize(), onClose = { navController.popBackStack() })Open and close the launcher's chat from code with Kavchat.controller.setPresented(true) and setPresented(false).
Views (no Compose in your app)
Kavchat.open(context) // starts KavchatActivityFrom Java: Kavchat.open(context);. The activity uses Compose internally, but your app does not need to.
Identity token
Identify the signed-in user with a JWT your backend signs with the secret key (see Identify users). It is sent as Authorization: Bearer <token>. Identified users can see releases limited to testers, and may send the contact form without an email or a phone.
Kavchat.setUser(token = identityToken, name = "Dana") // after login
Kavchat.setUser(token = null) // after logoutChanging the user reloads the release and starts a new conversation, so one user's chat never shows up for another.
App screens: onScreen
A script button of type screen asks your app to open one of its screens. The chat closes first (the dialog of KavchatLauncher, or KavchatActivity), so the screen is visible:
Kavchat.onScreen = { screen, targetId ->
navController.navigate("$screen/${targetId.orEmpty()}") // e.g. "orders", "42"
}Without a handler such buttons do nothing. link buttons open only https links (in the browser) and tel links (in the dialer). For analytics, Kavchat.onEvent reports Ready, Unavailable, Open, Close, Effect and Ticket.
The screen list in the editor
Declare the screens your app can open, once in Kavchat.configure(..., screens = ...) (type KavchatAppScreen). The SDK sends the list to Kavchat by itself, and the script editor then offers these screens in a dropdown with their names, instead of a free text field. It also asks for an item id when a screen needs one, and warns about a button that points to a screen you did not declare. Nobody types the screen list by hand in the dashboard.
Kavchat.configure(
this, publicKey = "pk_live_...",
screens = listOf(
KavchatAppScreen("orders", "My orders"),
KavchatAppScreen("product", "Product page", needsTarget = true), // needs a targetId
),
)
// or later: Kavchat.registerScreens(listOf(...))idis the valueonScreenreceives: letters, digits,_,.and-, up to 40 characters.labelis the name the admin sees, up to 60 characters. Up to 100 screens. Invalid entries and duplicate ids are dropped.needsTarget: the button also carries an item id (for example a product id), andonScreenreceives it astargetId.- The list is sent in the background after the release loads, only when it changed or once a week. A failure is silent and retried at the next launch. The user never sees anything.
- The registered screens appear in the dashboard under Bot, Settings, "App screens", with the platforms that reported each one. A screen you removed from the app can be deleted there.
Theming
Colors come from the dashboard (primaryColor). Text on the brand color is white or near-black by WCAG contrast, and a color too light for text on white is replaced with near-black for links and buttons. The bot name, subtitle, avatar and launcher side (start or end) also come from the dashboard, so they change without an app update. Surfaces and typography follow your MaterialTheme.
The "Powered by Kavchat by maxsave" badge appears on all plans, with a link to kavchat.com. On Premium, you can hide it in the bot settings.
Languages and RTL
- The UI language is the
localepassed toconfigure, else the device language if translated (he, en, ar, ru, es, fr, de, pt, it, tr), else the script language, else English. - Matching always uses the script language (stop words, Hebrew and Arabic prefixes).
- Hebrew and Arabic set
LocalLayoutDirectionto RTL for the whole chat. Nothing is flipped by hand: usestartandendif you wrap the composables. Keepandroid:supportsRtl="true"in your app manifest.
AI answers (Premium)
There is nothing to set up in your app. When AI answers are turned on in the dashboard (on your own AI provider key), a typed question that no script matches is sent to Kavchat, and the chat shows a typing indicator while it waits, for up to 20 seconds. The answer is shown as plain text with a small "AI answer" label in the user's language, followed by a button for a related topic when there is one, and "Talk to our team".
If there is no answer, or the request fails, takes too long or hits the limit (10 answers per conversation every 15 minutes), the chat shows its regular "no match" reply. The question still appears in the unanswered questions report, and AI answers are kept in the saved conversation like any other message.
Live chat with a representative
There is nothing to set up in your app. When live chat is turned on in the dashboard, the chat in your app behaves exactly like the website widget.
- The option appears only when live chat is on in the published release. When the bot shows "Talk to our team", the SDK checks whether a representative is free (the answer is cached for 30 seconds). If one is, a "Talk to a representative" button appears before it. If not, only the contact form is offered, with a short line above it that says why: outside business hours (with the time they are back) or everyone is busy.
- Before the chat, a short form asks for a name, an email or a phone, a department (only when more than one is open) and an optional first message. Guests must leave an email or a phone; users identified with an identity token need neither. If nobody is free by the time it is sent, the contact form opens with what was already typed.
- While waiting, the chat shows the time left until it becomes a request and a "Leave a message instead" button. The wait is set in the dashboard (2 minutes by default). Messages can be sent while waiting, and the representative sees them. If nobody is free in time, the chat is saved as a regular request and its number is shown.
- During the chat you see the representative's name, a line when someone joins (also after a transfer), a typing indicator and an "End chat" button. Messages are plain text only, up to 2000 characters, without links. A message the server has not confirmed yet shows "Sending..."; after repeated failures you can tap it to try again. A retry never creates a duplicate.
- After any disconnect the SDK waits a little (longer each time), fetches what it missed and reconnects. Messages are always shown in order and without duplicates. When the streaming connection does not work (for example behind a corporate proxy), the SDK polls the server for a while instead.
- When the app goes to the background the connection closes; when it comes back, the SDK fetches what it missed and reconnects. An ongoing chat continues after the app is closed and opened again, for up to 12 hours.
- There are no push notifications in this version. Messages arrive only while the app is open, and a reply sent while the app was in the background appears as soon as the user returns.
- The chat credential is kept in memory, and on the device only encrypted with an Android Keystore key. It never goes into a URL or a log. It is deleted when the chat ends, becomes a request or expires, and when
setUserswitches to another user.
Optional: set Kavchat.controller.livePage to tell the representative which screen the user came from.
Questions, conditions and leads
No app configuration is needed. A script can ask for details (a name, phone number, email, number or free text), use known information to decide what happens next and send a lead.
- Matching keyboard: When the bot is waiting for an answer, the text field opens a phone, email or numeric keyboard. For name questions, the keyboard capitalizes the first letter of each word. If the answer is invalid, the bot responds with a short message in the chat language and the field is highlighted. Optional questions show a "Skip" button. Entering "Cancel" in any supported language exits the question.
- Phone: Numbers without
+use the workspace's default country, set in the dashboard settings. - Lead: A lead step shows the consent text with "Send" and "No, thanks" buttons, followed by the confirmation message. The lead is queued on the device and sent to the server. If there is no network connection or the server is unavailable, sending is retried, including on the next launch and after
reload(). The server ignores duplicates. - Prefill: The contact form and live chat request form are filled in with the collected name, email and phone number. All collected values are attached to the request or the live chat request. Questions before a live chat (Premium) are asked before connecting.
- Identity token: When you use
setUser, the token'sname,emailandphonefields fill in the answers to the matching questions, and the bot skips them. - Current screen: Conditions can check the current screen. Set
Kavchat.controller.livePage(for example,"checkout").
The collected values are personal information. They remain in the conversation stored on the device and are sent only to leads, requests and live chats, never to analytics.
Offline and caching
The last release is cached in SharedPreferences with its ETag and revalidated with If-None-Match (304) on each launch. Without network the cached copy is used and a banner says so. When the bot is off, limited to testers, or out of quota, nothing is shown. An open conversation is kept for 30 minutes of inactivity, so leaving the chat or the app does not restart it. The conversation path is reported two seconds after the last action, and right away when the app goes to the background.