Dashly for Android supports API 21 and above.
Detailed SDK documentation is available at developers.dashly.io.
Currently, Dashly for Android can be installed using gradle.
To do this, add the repository to the project build.gradle file:
allprojects {
...
repositories {
...
maven { url "https://raw.github.com/carrotquest/android-sdk/dashly" }
maven { url "https://jitpack.io" }
}
}
Specify the dependencies in your application's build.gradle file:
android {
...
packagingOptions {
exclude 'META-INF/*.kotlin_module'
}
}
dependencies {
...
implementation 'io.carrotquest:android-sdk:3.5.0-usRelease'
}
The library uses Java 17. If your project uses a Java version below 17, add the following settings:
android {
...
compileOptions {
sourceCompatibility '17'
targetCompatibility '17'
}
}
Version 3.0.0 is a major update with breaking changes to the public API. What to take into account when upgrading:
setDebug(boolean) / isDebug() are removed — the level is set via setLogLevel(SdkLogLevel) with the values NONE, ERROR, WARN, INFO, DEBUG, VERBOSE. The default is NONE: the SDK writes nothing to the logs, including in release builds (previously some logs were always emitted). Additionally, you can receive log records directly in your own code via setLogSink(...) (for example, forward them to your logger or crash reporter) and take a point-in-time snapshot of the SDK state for bug reports via getDiagnostics(). Sensitive data (tokens, e-mails, identifiers) is masked until setLogIncludeSensitive(true) is called. Usage examples are in the «Initialization» section.addStateObserver / getStateFlow / addAuthStateObserver / getAuthStateFlow / addSessionExpiredObserver / getInitObservable, as well as the DashlyState / DashlyAuthState models). Session recovery is now automatic: take operation results from their Callback, and the initialization status from Dashly.isInit().Cancellable. Subscription methods (for example, setUnreadConversationsCallback) return a Cancellable — call .cancel() to unsubscribe.UserProperty / Operation consolidated. Operation is a single enum io.carrotquest_sdk.android.models.Operation with UPPER_CASE values (set_once → SET_ONCE, update_or_create → UPDATE_OR_CREATE, etc.). The UserProperty.operation field is no longer a public mutable field — it is read via getOperation(), and the class is now immutable.CarrotSDK.Callback callback type is removed → top-level io.carrotquest_sdk.android.Callback<T>; the branded Carrot.Callback / Dashly.Callback are kept as interchangeable subtypes.Map<String, String>. The RemoteMessage overloads and sendFcmToken(...) are removed — use sendPushToken(token) and the Map variants (see the «Notifications» section).If your application has user authentication, call it at the start of the application — the best place is the onResponse callback of setup. This prevents unnecessary anonymous user occurrences:
Dashly.setup(this, yourApiKey, object : Dashly.Callback<Boolean> {
override fun onResponse(result: Boolean) {
if (result) {
Dashly.auth(userId, userAuthKey, object : Dashly.Callback<String> {
override fun onResponse(result: String?) { }
override fun onFailure(t: Throwable) { }
})
}
}
override fun onFailure(t: Throwable) { }
})
To use Dashly for Android, you need the API Key and User Auth Key. You can find these keys in the Settings > Developers tab:

To initialize Dashly, you need to execute the following code in your application's onCreate() method:
Dashly.setup(this, apiKey, callback)
To print detailed SDK logs to logcat during debugging, set the log level (the default is SdkLogLevel.NONE — the SDK writes nothing to the logs):
Dashly.setLogLevel(SdkLogLevel.DEBUG) // to turn off: Dashly.setLogLevel(SdkLogLevel.NONE)
Optionally, you can receive log records in your own code (for example, forward them to your logger/crash reporter) and take a point-in-time snapshot of the SDK state for bug reports:
Dashly.setLogSink { entry -> myLogger.log(entry.category.toString() + " " + entry.message) }
// sensitive values (tokens/e-mails/identifiers) are masked by default;
// show them in full (for local debugging only):
Dashly.setLogIncludeSensitive(true)
val report = Dashly.getDiagnostics().toFormattedString()
If your application includes user authentication, you can pass the user id to Dashly. There are two ways to authenticate: directly pass the userAuthKey, or send a hash generated on your backend. Upon successful login, the dashly_id property value is returned in the callback.
Dashly.auth(userId, userAuthKey, callback)
Dashly.hashedAuth(userId, hash, callback)
To change the user, you need to first call the deinitialization method, and then re-call the initialization and (optionally) authentication methods:
Dashly.deInit(object : Dashly.Callback<Boolean> {
override fun onResponse(result: Boolean) {
Dashly.setup(this, yourApiKey, callbackSetup)
}
override fun onFailure(t: Throwable) {
}
})
You can set user properties using:
Dashly.setUserProperty(userProperty)
Dashly.setUserProperty(userPropertyList)
To describe user properties, use the UserProperty class (io.carrotquest_sdk.android.models.UserProperty):
public UserProperty(String key, String value)
public UserProperty(Operation operation, String key, String value)
Operation is the enum io.carrotquest_sdk.android.models.Operation with UPPER_CASE values (UPDATE_OR_CREATE, SET_ONCE, ADD, DELETE, APPEND, UNION, EXCLUDE). For more details on operations, please refer to the «User Properties» section.
Attention!
The key field cannot start with the $ symbol.
For setting system properties, two classes CarrotUserProperty and EcommerceUserProperty are implemented (package io.carrotquest_sdk.android.models).
To track events, use:
Dashly.trackEvent(eventName)
You can specify additional parameters for an event. Build them with the type-safe EventParams builder — the SDK serializes the values to JSON itself (you no longer need to pass a JSON string manually):
Dashly.trackEvent("purchase", EventParams.builder()
.put("item", "book")
.put("price", 9.99)
.put("gift", true)
.build())
put(...) is overloaded for String/Int/Long/Double/Boolean.
The SDK offers the ability to track navigation within the application to launch various trigger messages on specific screens if needed. Use the following method for this:
Dashly.trackScreen(screenName)
To pass UTM tags from a link, use:
Dashly.trackUtm(url)
The method extracts UTM parameters from the query string of the provided URL, records them as events, and sets the corresponding user properties. The typical use case is calling this method when the application is opened via a deep link:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
intent?.data?.toString()?.let { Dashly.trackUtm(it) }
}
You can retrieve a list of identifiers for the conversations that are currently unread. This is the only SDK method that throws an exception (CarrotException) — call it inside a try/catch:
try {
val unread = Dashly.getUnreadConversations()
} catch (e: CarrotException) {
// the SDK is not initialized or the user is unavailable
}
You can also subscribe to changes in the list of unread conversation identifiers:
Dashly.setUnreadConversationsCallback(callback)
You can give the mobile app user the ability to access the chat with an operator from anywhere. This can be accomplished in two ways—using a floating button or directly calling the chat opening method at any desired time.
Essentially, this is a user interface element inheriting from ConstraintLayout. You can embed it into your layout:
<io.carrotquest_sdk.android.ui.fab.FloatingButton
android:id="@+id/cq_sdk_float_button"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cq_location_fab="BOTTOM_RIGHT"
app:cq_visibility_background="false"
app:cq_icon_fab="@drawable/ic_send"
app:cq_margin_fab="8dp"
app:cq_show_social_labels="false"
app:cq_auto_hide_fab="true"
/>
This element has its own attributes:
- app:cq_location_fab dictates the placement of the floating button relative to its parent container. There are 4 possible positions: TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT; default is BOTTOM_RIGHT.
- app:cq_visibility_background controls the visibility of the dimming effect when the floating button is pressed. Default is true.
- app:cq_icon_fab sets the icon for the floating button. Default is @id/ic_cq_message.
- app:cq_margin_fab specifies the margins of the floating button relative to its parent container. Default is 16dp.
- app:cq_show_social_labels manages the visibility of labels next to social media icons. Default is true.
- app:cq_auto_hide_fab determines automatic hiding of the chat button when the internet is unavailable. Default is false.
Available methods for configuring and managing the floating button's behavior:
/**
* Show the floating button
*/
public void showFab()
/**
* Hide the floating button
*/
public void hideFab()
/**
* Show integration buttons
*/
public void expandMenu()
/**
* Hide integration buttons
*/
public void collapseMenu()
/**
* Set chat icon
* @param iconFAB Icon
*/
public void setIconFAB(Drawable iconFAB)
/**
* Set button margins from screen edges
* @param margin Margin value
*/
public void setMarginFAB(int margin)
/**
* Set button location
* @param location Button location
*/
public void setLocationFAB(LocationFAB location)
You can also open the chat by executing the following code from any location (post initialization):
Dashly.openChat(context)
The SDK supports two push notification providers - Firebase Cloud Messaging and Huawei Push Kit.
First, you need to obtain a key and send it to Dashly. You can find the field for entering the key in Settings > Developers > Push notifications for SDK. The setup process for Firebase Cloud Messaging is described here.
If you are already using Firebase Cloud Messaging for your push notifications, to ensure that push notifications work correctly in the SDK, you need to edit your FirebaseMessagingService. This is necessary to pass the token and our messages into the SDK. Example:
class MyFirebaseMessagingService : FirebaseMessagingService() {
override fun onMessageReceived(message: RemoteMessage) {
val pushData: Map<String, String> = message.data
if (Dashly.isDashlyPush(pushData)) {
Dashly.sendPushNotification(pushData, this)
} else {
// Your code
}
}
override fun onNewToken(token: String) {
Dashly.sendPushToken(token)
super.onNewToken(token)
}
}
To deliver notifications to users with devices without Google services, you can use Huawei's push notification delivery service. First, you need to integrate HPK into your application. Instructions can be found here. Then, in Settings > Developers > Push notifications for SDK, you need to provide the Client ID, Client Secret, and Webhook Secret. Next, modify the service inherited from HmsMessageService. Example:
class MyHuaweiPushKitService : HmsMessageService() {
override fun onMessageReceived(remoteMessage: RemoteMessage?) {
val pushData: Map<String, String> = remoteMessage?.dataOfMap ?: HashMap()
if (Dashly.isDashlyPush(pushData)) {
Dashly.sendPushNotification(pushData, this)
} else {
// Your code
}
}
override fun onNewToken(token: String?) {
Dashly.sendPushToken(token)
super.onNewToken(token)
}
override fun onNewToken(token: String?, p1: Bundle?) {
Dashly.sendPushToken(token)
super.onNewToken(token, p1)
}
}
You can change the icon and color of notifications for new messages. To set the icon for notifications, call the following method after initializing the SDK:
Dashly.setNotificationIcon(R.drawable.ic_notification_icon)
Alternatively, add an icon named ic_cq_notification.xml in the res/drawable directory. To set the notification color, specify a color named colorCqNotify with your desired value in the resource file:
<color name="colorCqNotify">#EF7F28</color>
If you want to receive information about new messages in the SDK from anywhere in your application, you can implement a BroadcastReceiver. Example implementation:
public class MyNewMessageBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if(intent.hasExtra(NotificationsConstants.CQ_SDK_NEW_MESSAGE_ARG)) {
IncomingMessage incomingMessage = (IncomingMessage) intent.getSerializableExtra(NotificationsConstants.CQ_SDK_NEW_MESSAGE_ARG);
if (incomingMessage != null) {
Toast.makeText(context, incomingMessage.getText(), Toast.LENGTH_SHORT).show();
}
}
}
}
IncomingMessage is a class that describes the incoming message.
Next, you need to register it:
MyNewMessageBroadcastReceiver messageReceiver = new MyNewMessageBroadcastReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(NotificationsConstants.CQ_SDK_NEW_MESSAGE_ACTION);
registerReceiver(messageReceiver, filter);
Important! If the application is closed and the user opens the chat by clicking a push, your start activity will not launch. The application will close along with the closure of the chat. To fix this, you can pass the full name of the activity that should launch when the chat is closed:
Dashly.setParentActivityClassName("io.test.MainActivity");
There are methods to unsubscribe a particular user from push notifications and from all campaigns in general.
A method for unsubscribing from push notifications:
Dashly.pushNotificationsUnsubscribe()
A method for unsubscribing from all push campaigns:
Dashly.pushCampaignsUnsubscribe()