Docs

Events & Screen Tracking

Track custom events and screen views in your Android app with the Grovs SDK

Custom events and screen tracking require Grovs Android SDK 3.0 or later.

Tracking custom events

Use track to record an event with optional properties and tags:

Kotlin
Grovs.track("checkout_completed", properties = mapOf("sku" to "abc", "total" to 42.0), tags = listOf("shop"))
Grovs.track("level_complete", properties = mapOf("level" to 5, "score" to 1200))
Grovs.track("button_tap")

Events are written to disk and sent in one batch every 30 seconds. A batch that fails stays on disk and is sent again on the next tick. Up to 1,000 events are kept on the device, and events older than seven days are dropped.

Before the SDK authenticates, events are stored and sent once authentication completes. On a launch that is resolving install attribution, events are held until attribution settles so they are credited to the right link — see Install attribution timing.

Event name rules

An event name must not be blank and must not be one of the reserved system event names:

view, open, install, reinstall, app_open, time_spent, reactivation, user_referred, custom, screen_view

Rejected events are logged and dropped. Use trackScreenView for screen views rather than track("screen_view").

Property values

Properties support strings, booleans, standard numbers, string-keyed maps, lists, and arrays. The SDK sanitizes each value before sending:

  • Date, URL, and UUID are converted to strings, including when nested.
  • A value that cannot be represented in JSON is dropped on its own and everything else is kept: a list element is removed from its list, a map entry from its map, a top-level property from the event. This covers NaN, infinity, other types such as enums, sets, or arbitrary objects, a map with any non-string key (the whole map is dropped), a reference back to an enclosing collection, and anything nested more than 16 levels deep. Dropped top-level properties are logged.
  • BigInteger and BigDecimal values beyond the Double range are dropped like infinity.
  • If the serialized properties exceed 8 KB of UTF-8, or traversal exceeds 8,192 values, the whole properties map is omitted and the event is still recorded.

The same rules apply to trackScreenView properties.

Tags

Tags are capped at 20 per event, each up to 255 characters. Set global tags to attach them to every subsequent event:

Kotlin
Grovs.setGlobalTags(listOf("android", "production"))
 
Grovs.setGlobalTags(null)  // clear

Global tags are merged with per-event tags, up to the combined cap of 20.

Tracking screen views

Kotlin
Grovs.trackScreenView("Checkout", properties = mapOf("step" to 2))

If the same screen is reported twice within one second the duplicate is dropped, which keeps a transient pause/resume or a re-attached Fragment from flooding the dashboard. The window does not deduplicate a genuine return to the same screen later.

Automatic screen tracking

autoTrackScreenViews defaults to true, so the SDK reports Activities and Fragments as screens on its own. When an Activity hosts Fragments, only the Fragment is reported and the host Activity's screen view is suppressed — the same rule iOS applies to container view controllers.

  • Modals (DialogFragment, BottomSheetDialogFragment) are treated as overlays, not screens, and are never reported under their own name. Opening one re-resolves the visible screen, so the screen underneath may be reported again unless it was reported within the last second. Call trackScreenView when a modal opens if you want the modal itself reported.
  • Tabs driven by the Navigation component, ViewPager2, setMaxLifecycle, or replace() transactions are tracked, because they resume the destination Fragment. The legacy hide()/show() pattern does not change Fragment lifecycle, so those switches are not tracked — use trackNavigation, setMaxLifecycle, or a manual trackScreenView in your tab handler.
  • Jetpack Compose destinations are not tracked automatically, because the SDK has no Compose dependency. Use trackNavigation or trackScreenView.

To turn automatic tracking off, pass autoTrackScreenViews = false when configuring:

Kotlin
Grovs.configure(this, "your-api-key", useTestEnvironment = false, baseURL = null, autoTrackScreenViews = false)

Grovs.setSDK(false) also stops automatic screen tracking, along with every other kind of collection.

Jetpack Navigation

For apps using Jetpack Navigation — Navigation Compose or route-based graphs — hand the SDK your NavController and every destination change is tracked, including bottom-navigation tabs, navigation rails, and Compose destinations the lifecycle-based tracker cannot see:

Kotlin
Grovs.trackNavigation(navController)

The screen name is derived from the destination's route, then its android:label, then its display name. Call it once per NavController, for example right after you set the graph. Repeat calls on the same controller are ignored, and the SDK holds only a weak reference, so it does not leak the hosting Activity or Fragment.

With Fragment-based navigation, trackNavigation overlaps the automatic tracker and can emit duplicate screen views under different names. Either disable automatic tracking (autoTrackScreenViews = false) and rely on trackNavigation, or use trackNavigation only for Compose and route-based graphs.

Screen name aliases

Map Activity and Fragment class names to friendlier names in the dashboard:

Kotlin
Grovs.setScreenAliases(mapOf("MainActivity" to "Home", "CartFragment" to "Shopping Cart"))

Aliases are synced to the backend after authentication. While the SDK is disabled the latest map is held and synced once it is enabled.

Sessions

Custom events and screen views carry an analytics session. A session survives brief trips to the background; returning to the foreground after more than 30 minutes starts a new one. A campaign resolved for a session stays attached to the events of that session, and a new session does not inherit it. Events already queued keep their original session and attribution.

Next steps

Edit this page on GitHubLast updated 2026-09-15