Skip to main content
The Android SDK shows Clarity’s support chat as a native bottom sheet or full-screen view. It pre-warms the chat in the background so it opens instantly, reports new replies for your own unread badge, and never crashes your app: every failure is reported to you instead. Requirements: Android 5.0 (API 21) or later, Kotlin 1.9 or later, and Android System WebView, which every Google-certified device has.

Get your credentials

In the cabinet, go to Settings > Mobile SDK, click Add Integration, choose Android and enter your app’s applicationId as the App ID. The integration dialog shows: The channel’s App ID must equal your app’s applicationId; the SDK sends it when the chat session starts and a mismatch is refused. These values are identifiers, not secrets, so shipping them in the APK is fine.
For an AppGallery build, create the channel with My mobile is Huawei checked and pass platform = ClarityPlatform.HUAWEI in ClarityConfig. Set it from your build flavour, not by probing the device. Chat works on devices without Google services; push notifications do not, because push is FCM-only.

Install

The SDK is on Maven Central, so no extra repository is needed.

Initialize

Call Clarity.init once, in Application.onCreate:

Configuration options

Identify the user

After your user logs in, and before the first open:
ClarityUser also takes phone, avatar and jwt.
  • Calling identify with a different externalId is a logout plus login: the previous user’s session is wiped, so conversations never leak between users.
  • Calling it again with the same externalId and new profile fields updates the profile and keeps the conversation.
  • On logout, call Clarity.resetSession().

Verify the user (signed identity)

An externalId alone is a claim the app makes about itself. To have Clarity trust it, your backend signs a short-lived JWT for the user with the channel’s identity secret, and the app passes it as jwt:
The secret is in the Android integration’s dialog under Identity verification. The token format, the claims and the Require a verified identity switch are the same as for the web widget: see Verify the visitor.
  • When the token expires, fetch a new one and call identify again with the same externalId. The conversation is kept.
  • A refused token makes show() report PAGE_LOAD_FAILED with code 401, and the message names the reason.
Never put the identity secret in the app. Anyone who extracts it from the APK can impersonate any of your users. ClarityUser.userHash is deprecated and was never verified; use jwt.

Open the chat

The chat appears only once it has loaded and painted. If it cannot load, the failure arrives through your listener instead of a blank sheet. Back, a tap outside the sheet and the chat’s own close button all dismiss it.

Badge your Help button

Every ClarityListener method is optional:
You can also read Clarity.unreadCount, Clarity.isWidgetVisible and Clarity.currentTicketStatus directly. unreadCount is a flag: 1 while unseen replies exist, else 0. Delivery while the chat is closed is best effort. When freshness matters, for example when the app returns to the foreground, call Clarity.refresh(). Missed replies and status changes arrive through the same listener.

Attributes and product events

These calls are safe from any thread at any time; values queue until the chat session is live. Product events are processed once product events are enabled for your organization; ask your Clarity contact.
If your workspace marks contact attributes as required, set them right after Clarity.init, before the chat first loads. A session missing a required attribute is refused, and show() reports PAGE_LOAD_FAILED naming the missing keys. With autoPreload = true the first load starts about 1.5 seconds after init; alternatively set autoPreload = false and call Clarity.preload() once the attributes are set.

Push notifications

While your app is running, replies that arrive with the chat closed already show a system notification; a tap reopens the chat. On Android 13 and later, request POST_NOTIFICATIONS yourself. The SDK never prompts. For replies while your app is killed or long in the background, forward your Firebase token and let Clarity handle its own pushes:
Also call Clarity.setDeviceToken(...) once at app start with the current token. Clarity.isClarityPush(data) tells you whether a message is Clarity’s without handling it.
Background push delivery is enabled per organization. Ask your Clarity contact about availability.

Attachments, voice and dictation

Customers can attach images and PDFs through the system file picker. No permissions or manifest entries are needed. If your organization uses voice calling or dictation in the chat, declare the microphone permission in your manifest:
With it declared, the chat offers a microphone button and asks for the permission on first use. Without it, no microphone button is shown.

Customization

The chat’s colours, logos, font and texts come from Settings > Widget in the cabinet, the same settings as the web widget. Per-app switches such as voice calling, dictation and the Inbox tab are in the Android integration’s dialog. In code you control the presentation (presentationMode, sheetHeightFraction), language and autoFocusInput.

API reference

Troubleshooting

Every failure arrives in onError as a ClarityError with a kind:
Check onError. HANDSHAKE_REJECTED means the organization id, integration key or App ID is wrong (the App ID must equal your applicationId), or the channel is Huawei and platform is not ClarityPlatform.HUAWEI, or the reverse. NETWORK means the device cannot reach baseUrl: check that Chrome on the same device opens it. In debug builds, a diagnostic screen names the reason.
On Android 13 and later, request POST_NOTIFICATIONS. The SDK never prompts for it.
Update to 1.6.1, which declares MODIFY_AUDIO_SETTINGS. On an older version, add <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> to your manifest.
show() reports PAGE_LOAD_FAILED with code 401. The message says whether the token was invalid, expired, missing or malformed. Check that your backend signs with the channel’s current identity secret and sets a valid exp.