Your mobile app can show the support chat full screen with our ready Flutter package. App users talk to the same AI assistant, knowledge base and agents as visitors of your website, the chat speaks the language of the app, and signed-in users enter it with just their phone number.
What the package does
- Shows the chat full screen on phones and tablets, as its own screen or as a tab.
- Takes the language of the chat from the app, not from the phone settings.
- Signs in app users with a token from your server, so the assistant can answer personal questions.
- Lets users attach photos and files from the camera, the gallery or the file system.
- Lets users record voice messages with the microphone button, where voice messages are available.
- Opens links from answers in an in-app browser, so the chat stays open underneath.
- Closes the chat with the Android back button and tells your app about it.
- Reports the number of unread replies for a badge on your chat button or tab.
- Keeps the conversation of a user who is not signed in, and clears the chat when a user signs out or another user signs in.
- Shows an error text with a Try again button instead of a blank screen.
The package does not deliver push notifications about new replies.
Get the package
We hand over the package when you connect your app: write to support@epavdesk.com. The current version is 0.4.0. Your developer receives three values:
- your support address, for example
https://support.example.com; - the ID of your live chat inbox, the same as in the website code;
- the address of the chat page.
The app needs Flutter 3.35 or newer, iOS 15.4 or newer, and on Android an up to date Android System WebView from Google Play.
Add the chat screen
import 'package:support_chat/support_chat.dart';
SupportChatView(
baseUrl: Uri.parse('https://support.example.com'), // your support address
inboxId: 'YOUR_INBOX_ID', // the live chat inbox ID
pageBase: 'CHAT_PAGE_ADDRESS', // the chat page address we give you
appVersion: 'com.example.app/3.4.1', // optional
userToken: () => backend.supportChatToken(), // a JWT from your server, or null
locale: () => appLocale, // optional, the app language
onClose: () => Navigator.of(context).pop(), // optional, the Android back button
onUnreadChanged: (count) => badge.value = count, // optional, unread replies
onError: (error) => reportError(error), // optional
)
SupportChatView is a complete screen: open it as a route or put it in a tab. It has no chat button of its own, your app decides where the chat opens. The chat page itself lives on our side, so its look, texts and behavior can change without a release of your app; a store release is needed only when you move to a new version of the package. appVersion sends nothing but the version of your app: it lets the designer tell how many installs will see a change. The page address carries your support address, the inbox ID, the language, version numbers and the platform, nothing that identifies a person.
The back button and unread replies
On Android, while the chat is on screen and onClose is set, the system back button goes to the chat first: the chat tidies up, for example stops a voice recording, and the package calls onClose. If the chat does not answer within half a second, onClose is called anyway. Your app closes the chat itself: pop the route, or switch to another tab if the chat is a tab. Without onClose, while the chat is loading or shows an error, and on iOS, the back button and the back swipe work as on any other screen.
onUnreadChanged gets the number of unread replies each time it changes, so your app can show a badge on its chat button or tab. It is counted only while the chat screen exists: a closed route counts nothing, while a chat tab kept alive in the background keeps counting.
The Domain list
The chat page in the app comes from its own address, the address of the chat page, not from your support address. Your platform always lets that page through, so nothing has to be added for the app, whether the Domain list of the live chat inbox (Setup > Security) is empty or filled. The list only limits which websites may show your website chat. See Live chat widget.
Sign in app users
The package calls your userToken callback every time the chat opens. The callback returns a JWT from your server, or null for a user who is not signed in. Your server signs the token with the Secret key of the live chat inbox (Setup > Security), exactly as for the website. The key must never be inside the app.
A phone number is enough to sign in:
import time
import jwt # PyJWT
token = jwt.encode(
{"external_user_id": str(user.id), "phone_number": user.phone, "exp": int(time.time()) + 600},
INBOX_SECRET,
algorithm="HS256",
)
external_user_id(up to 128 characters) andexpare required. A lifetime of 5 to 15 minutes is enough: after the exchange the chat keeps its own session.phone_number(up to 20 characters),first_name,last_nameandcontact_custom_attributesare optional. A contact without a name is shown to agents under the phone number.- Add
emailonly if your app has confirmed it: the sign-in is then linked to an existing contact with that email and its history.
If the platform rejects a token, the package asks your callback once more for a fresh one and reports an error only after that. A signed-in app user counts as verified, so custom tools marked Require verified contact can answer personal questions, for example about an order or a loan: see Custom tools. All token fields are described in Live chat widget.
Sign out
When a user signs out of your app, call:
await SupportChat.logout();
The chat session survives app restarts, so without this call the next person on the phone could see the previous user's conversations. If the call is missing, the package still starts a clean session when the token belongs to another user, or when an anonymous user follows a signed-in one. A user who is not signed in finds their conversation again each time they open the chat, and a user who chatted anonymously and then signs in keeps that history in their account.
Language
The chat's interface follows the language you return from the locale callback; without the callback it takes the app's current localization. This works while Language of the live chat inbox, tab General, is Auto-detect (browser language): a fixed language there applies to everyone. The chat's interface texts exist in English, Estonian, Russian, Ukrainian, German, French, Spanish, Italian and Brazilian Portuguese, among others; for another app language the chat takes the web view's language if it has that one, otherwise the inbox's Fallback language. The package's own menus and error texts exist in English, Russian and Ukrainian, other languages get English.
The assistant replies in the customer's language unless its Languages list holds exactly one language: see Assistant settings.
Attachments and links
- On Android the paperclip opens a menu with Take photo, Photo library and Choose file. On iOS the system shows its own choice.
- iOS needs these texts in
Info.plist, written for your users:
<key>NSCameraUsageDescription</key>
<string>To send a photo to support.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>To send an image to support.</string>
<key>NSMicrophoneUsageDescription</key>
<string>To record a voice message for support.</string>
- Android needs the
INTERNETpermission and<queries>entries for links, email, phone calls and the browser inAndroidManifest.xml; the example app of the package shows them. If your app declares theCAMERApermission, it must be granted before the user takes a photo, and the package does not ask for it: your app does. - Links from answers and attachments open in an in-app browser, so the chat stays where it was. Email and phone links open in the matching apps.
Voice messages
The microphone button appears in the app when speech recognition is set up, files are allowed in the chat and Voice messages is not switched off on the designer's App tab. The package asks the phone for permission at the first tap. On Android add:
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
Without this line the chat works, but recording does not start and a hint suggests typing. On iOS the NSMicrophoneUsageDescription text above is enough. Voice messages need version 0.3.0 of the package or newer. More in Voice messages.
The look of the chat in the app
The look is set in the live chat inbox, tab Designer, tab App. It is kept apart from the website on purpose: a change for the website never alters an app that is already in the stores.
- Changes on the App tab wait until you press Apply to the app (or Discard). Then press Save on the settings page, and the app picks them up.
- Check on a device gives a link to open on a phone. For half an hour it shows your draft, not what users see now.
- Font and Vibration on a reply need a newer package than the current 0.4.0, so current apps ignore them. The designer warns about such settings and shows what share of installs will see the change.
When something goes wrong
The chat shows a short message with a Try again button, and your onError callback gets a code:
| Code | When |
|---|---|
invalidConfig |
The support address is not a bare https address such as https://support.example.com, or the inbox ID is not valid. |
network |
No connection, the platform answered with a server error, or the chat page did not load. httpStatus holds the status code when the platform answered. |
inboxUnavailable |
The inbox is turned off or deleted. httpStatus holds the status code of the platform's answer. |
authFailed |
The callback failed or returned a token without external_user_id, or the platform rejected the token twice. |
timeout |
The chat did not load within 30 seconds. |
webViewFailed |
The web view could not be created. |
Version 0.4.0 removed the code sessionResetFailed, which no longer occurred: when you update the package, delete it from your error handling.