Android Integration Guide
Get your API key from https://app.revrag.ai.
Table of Contents
- Requirements
- Step 1 — Add the dependency
- Step 2 — Manifest permissions
- Step 3 — Initialize the SDK
- Step 4 — Identify the user
- Step 5 — Add the floating button
- Routing scenarios
- Button visibility control
- Voice calls & widget control
- Call behavior
- Events
- Analytics helpers
- Observing all SDK events
- Cleanup on logout
- Configuration reference
- Troubleshooting
- Pre-ship checklist
Requirements
Step 1 — Add the dependency
In your module-levelbuild.gradle.kts:
mavenCentral() is already in every Android project.
The SDK transitively pulls in:
- LiveKit Android SDK (WebRTC)
- Lottie for Android
- Coil (image loading)
- Kotlin Coroutines
Step 2 — Manifest permissions
The SDK’sAndroidManifest.xml declares these permissions — they are auto-merged into your app via manifest merger. You do not need to add them manually.
Step 3 — Initialize the SDK
Create anApplication class and call initialize() in onCreate(). This must run once, as early as possible.
AndroidManifest.xml:
Step 4 — Identify the user
Call this right after your login flow completes:Step 5 — Add the floating button
Wrap your root composable withEmbedProvider.attach() in MainActivity. This overlays the draggable button on top of all your existing Compose content automatically.
Alternative — EmbedProviderComposable
If you already call setContent {} yourself or use a multi-Activity architecture:
EmbedProvider.attach() props
Routing scenarios
Screen tracking lets the agent know which screen the user is on. Choose the scenario that matches your navigation setup.Scenario A — Single NavHost (most common)
Pass theNavController to EmbedProvider. The SDK tracks screen changes automatically — no additional code required.
"home", "search", "product/{id}", etc.
Scenario B — Bottom navigation with multiple NavHosts
Each tab has its ownNavController. Pass the active one to EmbedProvider:
Scenario C — No NavController (manual screen tracking)
If you manage navigation yourself (custom back stack, Fragments, or plain Compose without NavController), fireSCREEN_STATE events manually:
Scenario D — Nested navigation (checkout flow inside tabs)
"cart", "payment", "confirmation", etc. as the screen names from the nested graph.
Button visibility control
By default the button shows on every screen. UseEmbedButtonVisibilityConfig to control this.
Show only on specific screens
Keep button visible across a flow (e.g. checkout)
Use a group with.CONTINUOUS continuity so the button doesn’t flash between screens:
Visibility rules (evaluated in priority order)
Voice calls & widget control
The floating button (FAB) and its call card handle everything on their own. These functions let you drive the same widget programmatically — start or end a call, check call state, and collapse or observe the card — without waiting for a user tap.Call control
Widget control
Call behavior
Behavior to know about while a call is active:Events
EventKeys reference
Sending events
Listen for agent call events
Agent lifecycle events reference
Listen to data events locally
Useon() / off() to observe any EventKeys event locally — for example to mirror USER_DATA into your own state. Pass the same callback reference to off() when removing it.
Analytics helpers
These helpers fireANALYTICS_DATA events with standardized payloads.
Events auto-fired by the SDK
Matching event names with EmbedAnalyticsEvents
The SDK fires its built-in events as ANALYTICS_DATA carrying an event_name. Match against these constants instead of hardcoding strings:
Utility methods
Observing all SDK events
The SDK emits its own analytics / lifecycle events (widget taps, call start, mic permission, rage-clicks, tool triggers, errors…) — all asANALYTICS_DATA events carrying an event_name. Drop this helper into your app to log them all in one place or forward them to your analytics.
Usage
Full helper
Cleanup on logout
Call this when the user logs out or switches accounts to prevent stale data from leaking into the next session.Configuration reference
EmbedButtonVisibilityConfig
EmbedButtonGroupConfig
EmbedButtonDelayPolicy
EmbedButton direct props
Troubleshooting
The button never appears
Cause A —initialize() not called or failed
Check Logcat for [EmbedSDK] tags:
Cause B — SDK not ready yet
initialize() is async. The button is hidden until isInitialized = true and appears automatically — no action required. To observe readiness:
Cause C — Screen excluded by visibility config Check
excludedScreens and allowedScreens. Screen names are case-sensitive and must match exactly what’s in your NavGraph routes or what you pass to SCREEN_STATE.
Upgrading from 1.0.7 → 1.0.8
Drop-in replacement. No code changes required — bump the version string only. 1.0.8 adds the host-callable call-control API (startCall / endCall / isCallActive), widget control (collapseWidget / isWidgetExpanded), and the EmbedAnalyticsEvents constants; all existing 1.0.7 code keeps working unchanged.
Upgrading from 1.0.6 → 1.0.7
Drop-in replacement. No code changes required — bump the version string only. If you were blocked on 1.0.6 by errors like:ai.revrag.shaded.ktor.*, so your app’s Ktor version no longer matters.
Class 'X' was compiled with an incompatible version of Kotlin
Cause: Your project is on Kotlin 1.9 or earlier. The SDK is compiled with Kotlin 2.0.21 and the K1 compiler cannot read Kotlin metadata 2.x.
Fix: bump your project’s Kotlin version to 2.0+ in your root build.gradle.kts:
Could not resolve ai.revrag:embed-android:1.0.8
Cause: Dependency not cached, or stale Gradle cache.
https://central.sonatype.com/artifact/ai.revrag/embed-android
Confirm mavenCentral() is in your settings.gradle.kts:
Button stuck at top-left corner
Cause:EmbedProviderComposable is not at the root of the Compose tree.
Audio plays through speaker instead of Bluetooth headset
Cause:BLUETOOTH_CONNECT runtime permission denied (Android 12+).
Direct the user to app settings:
Analytics events missing from dashboard
Check in this order:USER_DATAwas sent with a validapp_user_idbefore other eventsinitialize()completed successfully (isInitialized == true)- Device has internet connectivity
- The SDK rate-limits to 5 req/s — bursts are queued, not dropped
User identity leaks between accounts
Always callclearStorageCache() on logout before the next user logs in:
Pre-ship checklist
Basic setup
-
ai.revrag:embed-android:1.0.8added and Gradle synced -
Applicationclass created and registered inAndroidManifest.xml -
EmbedSDK.initialize()called inApplication.onCreate() -
USER_DATAevent sent withapp_user_idimmediately after login -
EmbedProvider.attach()wraps the root composable inMainActivity -
clearStorageCache()called on logout
Screen tracking
-
NavControllerpassed toEmbedProvider(Scenario A/B), orSCREEN_STATEfired manually (Scenario C) - Nested graphs tracked correctly (Scenario D if applicable)
Visibility
-
visibilityConfigconfigured if the button should not show on all screens - Screen names in config match routes exactly (case-sensitive)
Production readiness
- Error handling in
EmbedSDK.initialize()onResultcallback - Agent event listeners registered and de-registered in
onDestroy - If driving calls from your own UI,
USER_DATAis sent beforestartCall() - Tested on a physical device — microphone permission dialog does not appear in emulator
Support
- Issues: GitHub Issues
- Docs: Revrag Documentation
- Dashboard: app.revrag.ai