trackEvent method
Records an event the app performed, such as a purchase.
Queued and sent in batches alongside campaign analytics; never blocks.
The name and properties are also evaluated against Digia-owned rules.
Implementation
Future<void> trackEvent(
String eventName, {
Map<String, Object?> properties = const {},
}) async {
if (!_initialized) {
_log.e('trackEvent() ignored — called before initialize()');
return;
}
_log.d('trackEvent (name=$eventName, '
'properties=${properties.keys.join(',')})');
// An invalid call is not a signal: nothing is queued and no rule is
// evaluated. One setup-mistake health event per launch, with a bounded
// sample of the offending name.
// Names are trimmed, as the server does, so both validate the same name.
eventName = eventName.trim();
final limits =
_services?.appEventsService.limits ?? AppEventLimits.defaults;
if (!isValidAppEventName(eventName, limits)) {
final sample = eventName.length > limits.nameMaxLength
? eventName.substring(0, limits.nameMaxLength)
: eventName;
_log.w(
'trackEvent dropped — invalid app event name',
stage: TimelineStage.session,
reason: TimelineReason.appEventInvalid,
extras: {'event_name': sample},
);
return;
}
final cleaned = cleanAppEventProperties(properties, limits);
if (cleaned.dropped.isNotEmpty) {
// The event is kept; only the values the backend can't store go.
_log.w(
'trackEvent($eventName) dropped properties the backend cannot store '
'(a bad value, a long key, or too many): ${cleaned.dropped.join(', ')}',
stage: TimelineStage.session,
reason: TimelineReason.appEventInvalid,
extras: {'event_name': eventName},
);
}
properties = cleaned.properties;
final signal = EventSignal(eventName, properties);
// Before the enqueue, so a wait cannot end while this event is in flight,
// even when the bus queues the signal behind one being handled.
_engine.cancelWaits(signal);
// Started first, so the event is queued before anything a rule emits. The
// rules do not wait for the queue write or a batch flush.
final tracked = _services?.appEventsService.track(
eventName,
properties: properties,
);
_engine.send(signal);
try {
await tracked;
} catch (error) {
_log.e('trackEvent() analytics failed — continuing', error: error);
}
}