Android SDK
Integrate Klero feedback, roadmap, changelog, surveys, and widgets into your Android app.
Requirements
- Android SDK 21+ (Android 5.0 Lollipop)
- Kotlin 1.9+
Installation
Add JitPack repository to your root build.gradle.kts:
dependencyResolutionManagement {
repositories {
maven { url = uri("https://jitpack.io") }
}
}Then add the dependency:
dependencies {
implementation("com.github.klero-ai:klero-android:0.1.0")
}Quick Start
Any Module with KleroEmbedView
KleroEmbedView is the generic embed view that supports all Klero module types.
import com.klero.sdk.KleroConfig
import com.klero.sdk.KleroEmbedView
import com.klero.sdk.KleroEmbedType
val config = KleroConfig(projectSlug = "myproject")
// Feedback board
val feedback = KleroEmbedView(this, config, KleroEmbedType.FEEDBACK)
// Roadmap
val roadmap = KleroEmbedView(this, config, KleroEmbedType.ROADMAP)
// Changelog
val changelog = KleroEmbedView(this, config, KleroEmbedType.CHANGELOG)
// Widget (floating button with panel)
val widget = KleroEmbedView(this, config, KleroEmbedType.WIDGET)Add to your layout:
val container = findViewById<FrameLayout>(R.id.container)
container.addView(feedback)Or set as content view:
setContentView(feedback)Survey with KleroSurvey
For surveys, use the dedicated KleroSurvey view which provides survey-specific event callbacks:
import com.klero.sdk.KleroConfig
import com.klero.sdk.KleroSurvey
import com.klero.sdk.KleroSurveyListener
val config = KleroConfig(projectSlug = "myproject")
val survey = KleroSurvey(this, config, "01ABC123...")
survey.listener = object : KleroSurveyListener {
override fun onComplete(surveyUlid: String, responseUlid: String, answers: Map<String, Any>) {
println("Completed: $responseUlid")
}
override fun onClose(surveyUlid: String, completed: Boolean) {
println("Closed, completed: $completed")
}
override fun onError(surveyUlid: String, error: String) {
println("Error: $error")
}
}
setContentView(survey)Jetpack Compose
KleroEmbedView in Compose
import androidx.compose.runtime.Composable
import androidx.compose.ui.viewinterop.AndroidView
import com.klero.sdk.*
@Composable
fun KleroEmbedComposable(
projectSlug: String,
embedType: KleroEmbedType,
customerToken: String? = null,
embedConfig: Map<String, Any> = emptyMap()
) {
AndroidView(
factory = { context ->
val config = KleroConfig(
projectSlug = projectSlug,
customerToken = customerToken
)
KleroEmbedView(context, config, embedType, embedConfig)
}
)
}
// Usage
@Composable
fun FeedbackScreen() {
KleroEmbedComposable(
projectSlug = "myproject",
embedType = KleroEmbedType.FEEDBACK
)
}KleroSurvey in Compose
@Composable
fun KleroSurveyComposable(
projectSlug: String,
surveyUlid: String,
customerToken: String? = null,
onComplete: ((String, String, Map<String, Any>) -> Unit)? = null
) {
AndroidView(
factory = { context ->
val config = KleroConfig(
projectSlug = projectSlug,
customerToken = customerToken
)
KleroSurvey(context, config, surveyUlid).apply {
listener = object : KleroSurveyListener {
override fun onComplete(
surveyUlid: String,
responseUlid: String,
answers: Map<String, Any>
) {
onComplete?.invoke(surveyUlid, responseUlid, answers)
}
}
}
}
)
}Widget Events
Listen for widget open/close events using KleroEmbedListener:
val widget = KleroEmbedView(this, config, KleroEmbedType.WIDGET)
widget.listener = object : KleroEmbedListener {
override fun onWidgetOpened() {
println("Widget panel opened")
}
override fun onWidgetClosed() {
println("Widget panel closed")
}
}Authentication
Pass a customer token to identify logged-in users:
val config = KleroConfig(
projectSlug = "myproject",
customerToken = "your-jwt-token"
)See the Authentication Guide for token generation.
Custom Base URL
For self-hosted or custom domain setups:
val config = KleroConfig(
projectSlug = "myproject",
baseUrl = "https://feedback.mycompany.com"
)Widget Touch Passthrough
KleroEmbedView with KleroEmbedType.WIDGET automatically handles touch passthrough. When the widget panel is closed, only the trigger button area (bottom-right corner) intercepts touches — all other touches pass through to views behind.
Cleanup
Always call destroy() when the view is no longer needed to clean up WebView resources:
override fun onDestroy() {
super.onDestroy()
embedView.destroy()
}API Reference
KleroConfig
| Property | Type | Required | Description |
|---|---|---|---|
projectSlug | String | Yes | Your Klero project slug |
baseUrl | String? | No | Custom base URL |
customerToken | String? | No | JWT token for user identification |
KleroEmbedType
| Value | Description |
|---|---|
FEEDBACK | Feedback board |
ROADMAP | Product roadmap |
CHANGELOG | Changelog / release notes |
WIDGET | Floating widget with panel |
SURVEY | Survey form |
KleroEmbedView
| Method | Description |
|---|---|
KleroEmbedView(context, config, embedType, embedConfig) | Create an embed view |
reload() | Reload the embed |
destroy() | Clean up resources |
KleroSurvey
| Method | Description |
|---|---|
KleroSurvey(context, config, surveyUlid) | Create a survey view |
open(surveyUlid?) | Open the survey |
close() | Close the survey |
reload() | Reload the survey |
destroy() | Clean up resources |
KleroSurveyListener
| Method | Description |
|---|---|
onComplete(surveyUlid, responseUlid, answers) | Survey completed |
onClose(surveyUlid, completed) | Survey closed |
onError(surveyUlid, error) | Survey failed to load |
KleroEmbedListener
| Method | Description |
|---|---|
onWidgetOpened() | Widget panel opened |
onWidgetClosed() | Widget panel closed |
Permissions
The SDK requires the INTERNET permission, which is automatically merged from the SDK's manifest.