vakaGitHub

Install Vaka in an Android app (Kotlin)

Project: your-project · Endpoint: https://vaka.example.com · Ingest key: vk_your_ingest_key

These steps are written to be followed by a coding agent. Do them in order and verify at the end. Requirements: minSdk 21+, Android Gradle Plugin 8.x. The SDK has no dependencies besides the Android SDK and the Kotlin standard library.

1. Add the SDK and the Gradle plugin

In settings.gradle.kts, make sure mavenCentral() is listed in both pluginManagement.repositories and dependencyResolutionManagement.repositories (new projects already have it).

In the app module's build.gradle.kts:

plugins {
    id("com.android.application")
    // ...existing plugins...
    id("se.hellsoft.vaka") version "0.1.0"   // uploads the R8 mapping after each minified build
}

dependencies {
    implementation("se.hellsoft.vaka:vaka-android:0.1.0")
}

vaka {
    url.set("https://vaka.example.com")
    project.set("your-project")
    // The API token comes from the VAKA_TOKEN environment variable (or -Pvaka.token). Never commit it.
}

If the project uses a version catalog (gradle/libs.versions.toml), add the same coordinates there instead and reference them with alias(libs.plugins.vaka) / implementation(libs.vaka.android).

Building from source instead (if the artifacts cannot be resolved): clone https://github.com/ErikHellman/vaka next to the app, then in the app's settings.gradle.kts add includeBuild("../vaka/sdks/android/vaka-gradle-plugin") inside pluginManagement { } and includeBuild("../vaka/sdks/android") at the top level, and drop the version "0.1.0" from the plugin line. Gradle substitutes both automatically.

2. Initialise in the Application class

If the app has no Application subclass, create one and register it with android:name on the <application> element in AndroidManifest.xml. Then:

import se.hellsoft.vaka.Vaka
import se.hellsoft.vaka.VakaConfig

class App : Application() {
    override fun onCreate() {
        super.onCreate()
        Vaka.init(this, VakaConfig(
            key = "vk_your_ingest_key",
            endpoint = "https://vaka.example.com",
            release = BuildConfig.VERSION_NAME,   // must match the release the mapping is uploaded for
            environment = if (BuildConfig.DEBUG) "debug" else "production",
        ))
    }
}

Enable buildFeatures { buildConfig = true } in the app module if BuildConfig is not generated. The ingest key is write-only and safe to ship in the app. The SDK adds the INTERNET and ACCESS_NETWORK_STATE permissions through manifest merging. If https://vaka.example.com is plain http:// (local testing), the app also needs android:usesCleartextTraffic="true" or a network security config.

3. What you get automatically

4. Optional calls

Vaka.screen("Checkout")                          // Compose/Fragment screens (Activities are automatic)
Vaka.track("purchase", mapOf("plan" to "pro"))   // custom event (flat string/number/boolean props)
Vaka.captureException(e)                          // handled exception
Vaka.captureMessage("Payment provider slow", VakaLevel.WARNING)
Vaka.addBreadcrumb("cart", "Added item 42")
Vaka.setTag("flavor", BuildConfig.FLAVOR)
Vaka.identify("user-123")                         // opt-in only; Vaka.identify(null) clears it

For Jetpack Compose navigation, call Vaka.screen(route) from a NavController.OnDestinationChangedListener and consider autoScreenViews = false if the app has a single Activity. Do not call identify with emails or names unless the app's privacy policy allows it.

5. R8 mapping upload (release builds)

With isMinifyEnabled = true, the plugin adds uploadVakaMapping<Variant> and runs it after minify<Variant>WithR8. It needs an API token with write access (create one with the MCP tool create_token, the admin UI, or POST /api/v1/tokens):

export VAKA_TOKEN=vt_...
./gradlew :app:assembleRelease   # or bundleRelease; look for "Vaka: uploaded mapping.txt"

On CI, store VAKA_TOKEN as a secret. Without a token the build still succeeds and logs a warning (set failOnError.set(true) in the vaka { } block to fail instead). If release in VakaConfig is not versionName, set the same value with release.set(...) in the vaka { } block. Alternative without the plugin: vaka upload proguard --release <versionName> app/build/outputs/mapping/release/mapping.txt.

6. Verify

  1. Build and run the app (./gradlew :app:installDebug on a device or emulator). On an emulator, localhost on the host machine is 10.0.2.2.
  2. Trigger a test error, e.g. temporarily add Vaka.captureMessage("vaka install test", VakaLevel.ERROR) after Vaka.init, open the app, then send it to the background (or wait 10 seconds).
  3. Check with the API: curl -H "Authorization: Bearer $VAKA_TOKEN" https://vaka.example.com/api/v1/projects/your-project/issues, or the MCP tool list_issues. Sessions show up in GET /api/v1/projects/your-project/releases/health and screen views in GET /api/v1/projects/your-project/analytics/summary.
  4. Remove the test call.

If nothing arrives: set debug = true in VakaConfig and filter Logcat by the tag Vaka (expect sent batch: HTTP 202). An ingest key rejected line means the key is wrong or revoked.