Skip to content

Getting started

This page covers Gradle hosts — Android and Kotlin Multiplatform. An app written entirely in Swift installs the Swift Package instead: see Native iOS.

Install

Use the real artifacts in debug and the no-op mirrors in release, so release builds capture nothing and drop the UI/body-retention overhead:

dependencies {
    debugImplementation("io.github.asanre:verivent:0.10.1")
    releaseImplementation("io.github.asanre:verivent-no-op:0.10.1")

    // the on-device inspector UI:
    debugImplementation("io.github.asanre:verivent-ui:0.10.1")
    releaseImplementation("io.github.asanre:verivent-ui-no-op:0.10.1")

    // network capture for Ktor clients:
    debugImplementation("io.github.asanre:verivent-ktor:0.10.1")
    releaseImplementation("io.github.asanre:verivent-ktor-no-op:0.10.1")
}

verivent holds the models, store, redaction, the analytics sink and the web viewer; verivent-ui and verivent-ktor bring it along, so declare it yourself only when you call its API directly. The no-op mirrors declare the exact same classes and functions, so your call sites compile unchanged.

Upgrading from 0.6

log(..., userProperties = …) became log(..., sections = mapOf("User properties" to …)), and AnalyticsEntry.userProperties became AnalyticsEntry.sections. See extra parameter blocks.

Upgrading from 0.5

verivent-core and verivent-analytics merged into verivent (and their no-ops into verivent-no-op). Replace those coordinates with verivent / verivent-no-op; packages and APIs are unchanged, so no source edits are needed.

Skipping verivent-ui

verivent-ui is the only artifact that pulls in Compose. Leave it out if you inspect from the web viewer instead of on-device — everything else keeps working, and Compose never enters your dependency graph.

Capture network traffic

Install the plugin on your Ktor client:

val client = HttpClient(engine) {
    install(Verivent) {
        maxContentLength = 250_000                              // truncate bodies larger than this
        sanitizeHeader { it == HttpHeaders.Authorization }      // Authorization/Cookie/Set-Cookie are redacted by default
        sanitizeQueryParameter { it == "token" }               // common secret params are redacted by default
        sanitizeBody { it.replace(emailRegex, "██") }          // rewrite the stored preview only
        filter { request -> request.url.host != "metrics.internal" }
    }
}

Every option is a plain predicate — see Filters, redaction & annotations for the full list.

Capture analytics events

Verivent never talks to an analytics SDK. Wire your own analytics facade to log:

val sink = AnalyticsSink {
    filter { event -> !event.name.startsWith("debug_") }
    sanitizeProperty { key -> key in setOf("user_email", "user_id") }
    annotate { event -> if (event.name in ecommerceEvents) listOf(Annotation.Ecommerce) else emptyList() }
}

// from your facade, alongside the real SDK call:
sink.log("purchase", channel = "firebase", properties = mapOf("value" to 42.5))

See Hook your analytics facade for the pattern.

Tune retention

The store is an in-memory ring buffer with two drop-oldest limits: entry count and approximate bytes. Defaults are 500 entries and 20 MB. Reconfigure before traffic starts (it clears the store; the StateFlow survives, so an already-open inspector keeps working):

Inspector.configure(capacity = 1_000, maxTotalBytes = 40_000_000)

The same call renames the tool. title reaches every viewer — the inspector's header, the Android and iOS notifications, and the web page's tab and header — so a host that would rather ship its own name sets it once:

Inspector.configure(title = "Patata Inspector")

Unlike the limits, changing the title leaves the store alone. That covers every surface Verivent draws; the one name it cannot set is Android's task label, which is normally your app's anyway — see Where the Activity lands.

How the viewers group the timeline is set on the analytics logger instead — see Grouping.

Next: open the inspector.