How to add analytics to Android apps
This guide walks you through adding OpenPanel analytics to an Android application using the Kotlin SDK. You'll learn how to track events, identify users, and monitor screen views across your app.
OpenPanel works well for Android apps because it provides a lightweight, privacy-focused SDK that handles offline queuing and automatic system information collection. Unlike web SDKs, native apps require a client secret for authentication since CORS headers aren't available.
Prerequisites
- An Android project (minSdkVersion 21+)
- An OpenPanel account
- Your Client ID and Client Secret from the dashboard
Add the dependency
Start by adding the OpenPanel SDK to your app's build.gradle.kts file. The SDK is available through standard Gradle dependency management.
dependencies {
implementation("dev.openpanel:openpanel:0.0.1")
}The Kotlin SDK is currently in development, so check the GitHub repository for the latest version number before adding it to your project.
Initialize OpenPanel
Before you can track events, you need to initialize OpenPanel in your Application class. This ensures the SDK is available throughout your app and can properly manage its lifecycle.
import android.app.Application
import dev.openpanel.OpenPanel
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
OpenPanel.create(
context = this,
options = OpenPanel.Options(
clientId = "YOUR_CLIENT_ID",
clientSecret = "YOUR_CLIENT_SECRET"
)
)
}
}You also need to register your Application class in the Android manifest so the system knows to use it.
<application
android:name=".MyApplication"
...>
</application>If you're using dependency injection with Hilt or Dagger, you can provide OpenPanel as a singleton instead. This approach integrates better with modern Android architecture patterns.
import android.content.Context
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import dev.openpanel.OpenPanel
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Provides
@Singleton
fun provideOpenPanel(@ApplicationContext context: Context): OpenPanel {
return OpenPanel.create(
context,
OpenPanel.Options(
clientId = "YOUR_CLIENT_ID",
clientSecret = "YOUR_CLIENT_SECRET"
)
)
}
}Track events
Once OpenPanel is initialized, you can track events anywhere in your app by getting the SDK instance and calling the track method. Each event has a name and an optional map of properties.
import dev.openpanel.OpenPanel
class MainActivity : AppCompatActivity() {
private lateinit var op: OpenPanel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
op = OpenPanel.getInstance(this)
findViewById<Button>(R.id.signupButton).setOnClickListener {
op.track(
"button_clicked",
mapOf(
"button_name" to "signup",
"button_location" to "hero"
)
)
}
}
}The SDK is thread-safe, so you can call track from any thread without additional synchronization. This is particularly useful when tracking events from background operations or coroutines.
If you want to attach properties to every event automatically, use setGlobalProperties. This is helpful for including app version, build number, or environment information.
op.setGlobalProperties(
mapOf(
"app_version" to BuildConfig.VERSION_NAME,
"build_number" to BuildConfig.VERSION_CODE.toString(),
"platform" to "Android"
)
)Identify users
When a user logs in or you have information about who they are, call identify to associate their profile with tracked events. This enables user-level analytics and cohort analysis in your dashboard.
op.identify(
user.id,
mapOf(
"firstName" to user.firstName,
"lastName" to user.lastName,
"email" to user.email,
"plan" to user.plan
)
)When a user logs out, clear their data so subsequent events aren't attributed to them.
fun logout() {
op.clear()
}You can also increment numeric properties on user profiles. This is useful for tracking things like login counts or credits without needing to know the current value.
op.increment(user.id, "login_count", 1)Track screen views
Screen view tracking helps you understand navigation patterns and which parts of your app get the most attention. The simplest approach is to create a base activity that tracks screen views automatically.
import androidx.appcompat.app.AppCompatActivity
import dev.openpanel.OpenPanel
abstract class BaseActivity : AppCompatActivity() {
protected lateinit var op: OpenPanel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
op = OpenPanel.getInstance(this)
}
override fun onResume() {
super.onResume()
op.track(
"screen_view",
mapOf("screen_name" to this::class.simpleName ?: "Unknown")
)
}
}For Jetpack Compose, use a LaunchedEffect to track when a composable screen appears.
import androidx.compose.runtime.LaunchedEffect
import dev.openpanel.OpenPanel
@Composable
fun MainScreen(op: OpenPanel) {
LaunchedEffect(Unit) {
op.track(
"screen_view",
mapOf("screen_name" to "MainScreen")
)
}
// Your composable content
}If you want the SDK to automatically track app lifecycle events like app_opened and app_closed, enable automatic tracking during initialization.
OpenPanel.create(
context,
OpenPanel.Options(
clientId = "YOUR_CLIENT_ID",
clientSecret = "YOUR_CLIENT_SECRET",
automaticTracking = true
)
)Verify your setup
Run your Android app in an emulator or on a physical device and interact with a few screens and buttons. Open your OpenPanel dashboard and check the real-time view to see events arriving.
If events aren't appearing, check Logcat for error messages from the SDK. The most common issues are incorrect credentials or missing the clientSecret parameter. You can also use Android Studio's Network Profiler to verify that requests are being sent to OpenPanel's servers.
Next steps
The full Kotlin SDK reference covers additional options like event filtering and verbose logging. If you're building for multiple platforms, the React Native guide shows how to share analytics code across iOS and Android.


