Events & screen tracking
Track custom events and screen views in your Flutter app with the Grovs SDK.
Requires plugin 3.0.0 or later.
Tracking custom events
track records an event with optional properties and tags:
import 'package:grovs_flutter_plugin/grovs.dart';
final grovs = Grovs();
await grovs.track(
'checkout_completed',
properties: {'sku': 'abc', 'total': 42.0},
tags: ['shop'],
);
await grovs.track('level_complete', properties: {'level': 5, 'score': 1200});
await grovs.track('button_tap');The native SDK queues the event on the device and sends it in batches. Batching, retention, the hold during install attribution and analytics sessions behave as in a native app. See iOS and Android Events & Screen Tracking.
Event name rules
Names can't be empty or a reserved system name:
view, open, install, reinstall, app_open, time_spent, reactivation, user_referred, custom, screen_view
The native 3.1 SDKs also refuse the names Grovs uses for push and in-app reporting: 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 and journey_path.
The native SDK logs and drops rejected events. Use trackScreenView for screen views, not track('screen_view').
Property values
Properties cross the Flutter platform channel, so values must be channel-encodable: null, bool, num, String, List, or Map with string keys, nested to any depth. A DateTime, enum or custom object throws ArgumentError in the channel before anything is sent; convert it to a string first.
Natively, properties cap at 8 KB of serialized JSON and tags at 20 per event. The platform pages above cover values each SDK can't represent. The same rules apply to trackScreenView properties.
Tags
Global tags attach to every later event:
await grovs.setGlobalTags(['flutter', 'production']);
await grovs.setGlobalTags(null); // clearThe native SDK merges global and per-event tags, up to 20 combined.
Tracking screen views
await grovs.trackScreenView('Checkout', properties: {'step': 2});Use it for screens the automatic tracker can't see (tabs that switch without a route change) or to attach properties. The native SDKs drop a repeat of the same name within one second, so a manual call right after the observer reports the same route isn't double-counted.
Automatic screen tracking
Add Grovs.navigatorObserver to your MaterialApp (or CupertinoApp):
import 'package:flutter/material.dart';
import 'package:grovs_flutter_plugin/grovs.dart';
MaterialApp(
navigatorObservers: [Grovs.navigatorObserver],
routes: {
'/': (_) => const HomeScreen(),
'/product': (_) => const ProductScreen(),
},
);The observer reports a screen view on push, on replace (the new route) and on pop (the route revealed). Only PageRoutes count. Dialogs and bottom sheets are PopupRoutes and are skipped, as are routes in a Navigator the observer isn't attached to. Automatic screen views carry no properties.
How a screen name is chosen
The first non-empty result wins, then goes through screen aliases:
- Your
screenNameExtractor, if the observer has one. - The route's
RouteSettings.name. Named routes andpushNamedset it. - The route's runtime type, for example
MaterialPageRoute<dynamic>.
The runtime-type fallback is obfuscated in release builds. Name your routes or supply a screenNameExtractor for stable dashboard names.
Custom name resolution
Grovs.navigatorObserver is a shared GrovsNavigatorObserver. To resolve names yourself or observe a nested Navigator, construct your own. An observer attaches to one Navigator at a time, so create one per navigator:
import 'package:flutter/material.dart';
import 'package:grovs_flutter_plugin/grovs_navigator_observer.dart';
final observer = GrovsNavigatorObserver(
screenNameExtractor: (route) {
// Strip query parameters from names like '/product?id=42'
final name = route.settings.name;
return name?.split('?').first;
},
);
MaterialApp(navigatorObservers: [observer]);Returning null or an empty string falls through to the route name, then the runtime type. With a router package that creates its own Navigator, pass the observer through that package's observers option, not MaterialApp.navigatorObservers.
Native screen tracking is off
The plugin disables native automatic screen tracking. The hosting FlutterActivity and FlutterViewController are never reported, and the observer counts Flutter routes once. Native screens you present from platform code aren't tracked; call trackScreenView for them or track them natively.
Screen views from the observer and trackScreenView are also what in-app messages trigger on and what excluded screens match.
setSDK(false) stops screen views with all other collection. The observer still calls trackScreenView, but nothing is recorded while disabled.
Screen name aliases
Map raw screen names to friendlier dashboard names:
await grovs.setScreenAliases({
'/': 'Home',
'/product': 'Product',
'MaterialPageRoute<dynamic>': 'Untitled',
});Key by the raw name the observer would send: extractor result, route name or runtime type. The plugin applies aliases in Dart to every automatic screen view and forwards the map to the native SDK, which syncs it after authentication. Manual trackScreenView calls send the name you pass. Read the current map from Grovs.screenAliases.