Events & screen tracking
Track custom events and screen views in your Android app with the Grovs SDK.
Requires Android SDK 3.0 or later. Screen views and custom events can also trigger in-app messages (3.1).
Tracking custom events
track records an event with optional properties and tags:
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")How events are sent:
- Written to disk and sent in one batch every 30 seconds. A failed batch stays on disk and is retried on the next tick.
- Up to 1,000 events are kept on the device. Events older than seven days are dropped.
- Before authentication, events are stored and sent once it completes.
- While install attribution resolves, events are held so they credit the right link. See Install attribution timing.
Event name rules
Names can't be blank or a reserved system name:
view, open, install, reinstall, app_open, time_spent, reactivation, user_referred, custom, screen_view
Push, in-app and journey event names are refused too: in_app_viewed, in_app_clicked, in_app_dismissed, in_app_answered, in_app_commented, in_app_held, push_open, push_delivered, push_held, journey_entered, journey_held, journey_path. in_app_held, the push_* and the journey_* names are refused since 3.1.
Names are compared after trimming, ignoring case. Rejected events are logged and dropped. Use trackScreenView for screen views, not track("screen_view").
Property values
Supported: strings, booleans, standard numbers, string-keyed maps, lists and arrays. The SDK sanitizes each value, for track and trackScreenView alike:
Date,URLandUUIDbecome strings, including when nested.- Whole numbers are sent as whole numbers (
4, not4.0). - A value JSON can't represent is dropped on its own: a list element from its list, a map entry from its map, a top-level property from the event. Everything else is kept. Dropped top-level properties are logged.
- That covers
NaN, infinity, other types (enums, sets, arbitrary objects), maps with any non-string key (the whole map is dropped), references back to an enclosing collection, and nesting deeper than 16 levels. BigIntegerandBigDecimalbeyond theDoublerange are dropped like infinity.- Over 8 KB of UTF-8, or more than 8,192 values traversed, omits the whole properties map. The event is still recorded.
Tags
Up to 20 tags per event, each up to 255 characters. Global tags attach to every later event:
Grovs.setGlobalTags(listOf("android", "production"))
Grovs.setGlobalTags(null) // clearGlobal and per-event tags are merged, up to 20 combined.
Tracking screen views
Grovs.trackScreenView("Checkout", properties = mapOf("step" to 2))The same screen reported twice within one second is dropped, so a brief pause/resume or a re-attached Fragment doesn't flood the dashboard. A genuine later return to the screen still counts.
Automatic screen tracking
autoTrackScreenViews defaults to true: the SDK reports Activities and Fragments as screens. When an Activity hosts Fragments, only the Fragment is reported, as iOS does for container view controllers.
- Modals (
DialogFragment,BottomSheetDialogFragment) are overlays, 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 in the last second. To report the modal, calltrackScreenViewwhen it opens. - Tabs using the Navigation component,
ViewPager2,setMaxLifecycleorreplace()are tracked, because they resume the destination Fragment. Legacyhide()/show()doesn't change Fragment lifecycle, so it isn't tracked. UsetrackNavigation,setMaxLifecycleortrackScreenViewin your tab handler. - Jetpack Compose destinations aren't tracked automatically; the SDK has no Compose dependency. Use
trackNavigationortrackScreenView.
To turn it off, pass autoTrackScreenViews = false:
Grovs.configure(this, "your-api-key", useTestEnvironment = false, baseURL = null, autoTrackScreenViews = false)Grovs.setSDK(false) stops automatic screen tracking along with all other collection.
Jetpack Navigation
With Jetpack Navigation (Navigation Compose or route-based graphs), pass your NavController to track every destination change. That includes bottom-navigation tabs, navigation rails and Compose destinations the lifecycle tracker can't see:
Grovs.trackNavigation(navController)The name comes from the destination's route, then android:label, then its display name. Call it once per NavController, for example after setting the graph. Repeat calls are ignored. The SDK holds a weak reference, so it doesn't leak the host Activity or Fragment.
With Fragment-based navigation, trackNavigation overlaps the automatic tracker and can report duplicates under different names. Either set 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 dashboard names:
Grovs.setScreenAliases(mapOf("MainActivity" to "Home", "CartFragment" to "Shopping Cart"))Aliases sync after authentication. While the SDK is disabled, the latest map is held until it's enabled.
Sessions
Custom events and screen views carry an analytics session. Brief trips to the background keep the session; returning after more than 30 minutes starts a new one. A campaign resolved for a session stays with that session's events and isn't inherited by the next. Queued events keep their original session and attribution.