Files
stats/apps/public/content/guides/kotlin-analytics.mdx
Carl-Gerhard Lindesvärd 6ce9b5dd1b public: feature pages
2026-02-07 16:42:02 +00:00

269 lines
9.1 KiB
Plaintext

---
title: "How to add analytics to Android apps"
description: "Add privacy-first analytics to Android applications using OpenPanel's Kotlin SDK. Track events, identify users, and analyze behavior."
type: guide
difficulty: intermediate
timeToComplete: 10
date: 2025-12-15
updated: 2026-02-07
lastUpdated: 2025-12-15
team: OpenPanel Team
steps:
- name: "Add the dependency"
anchor: "install"
- name: "Initialize OpenPanel"
anchor: "setup"
- name: "Track events"
anchor: "events"
- name: "Identify users"
anchor: "identify"
- name: "Track screen views"
anchor: "screenviews"
- name: "Verify your setup"
anchor: "verify"
---
# 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](/features/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](https://dashboard.openpanel.dev)
## Add the dependency [#install]
Start by adding the OpenPanel SDK to your app's `build.gradle.kts` file. The SDK is available through standard Gradle dependency management.
```kotlin
dependencies {
implementation("dev.openpanel:openpanel:0.0.1")
}
```
The Kotlin SDK is currently in development, so check the [GitHub repository](https://github.com/Openpanel-dev/kotlin-sdk) for the latest version number before adding it to your project.
## Initialize OpenPanel [#setup]
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.
```kotlin
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.
```xml
<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.
```kotlin
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 [#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.
```kotlin
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.
```kotlin
op.setGlobalProperties(
mapOf(
"app_version" to BuildConfig.VERSION_NAME,
"build_number" to BuildConfig.VERSION_CODE.toString(),
"platform" to "Android"
)
)
```
## Identify users [#identify]
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.
```kotlin
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.
```kotlin
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.
```kotlin
op.increment(user.id, "login_count", 1)
```
## Track screen views [#screenviews]
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.
```kotlin
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.
```kotlin
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.
```kotlin
OpenPanel.create(
context,
OpenPanel.Options(
clientId = "YOUR_CLIENT_ID",
clientSecret = "YOUR_CLIENT_SECRET",
automaticTracking = true
)
)
```
## Verify your setup [#verify]
Run your Android app in an emulator or on a physical device and interact with a few screens and buttons. Open your [OpenPanel dashboard](https://dashboard.openpanel.dev) 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](/docs/sdks/kotlin) covers additional options like event filtering and verbose logging. If you're building for multiple platforms, the [React Native guide](/guides/react-native-analytics) shows how to share analytics code across iOS and Android.
<Faqs>
<FaqItem question="Why do I need a client secret for native apps?">
Native apps can't use CORS headers for authentication like web apps do. The client secret provides server-side authentication to ensure your events are properly validated. Keep this secret secure and never expose it in client-side web code.
</FaqItem>
<FaqItem question="Does OpenPanel work with Jetpack Compose?">
Yes. OpenPanel works with both traditional Views and Jetpack Compose. For Compose, use LaunchedEffect to track screen views when a composable appears, as shown in the screen tracking section above.
</FaqItem>
<FaqItem question="Can I track events when the device is offline?">
Yes. The SDK queues events locally when there's no network connection and sends them automatically when connectivity is restored. You won't lose events if users go through tunnels or airplane mode.
</FaqItem>
<FaqItem question="Is OpenPanel GDPR compliant?">
Yes. OpenPanel is designed for GDPR compliance with data minimization and full support for data subject rights. With self-hosting, you also eliminate international data transfer concerns entirely. See the [cookieless analytics guide](/articles/cookieless-analytics) for more details.
</FaqItem>
</Faqs>