trackEvent method

Future<void> trackEvent(
  1. String eventName, {
  2. Map<String, dynamic>? properties,
  3. Duration timeout = const Duration(seconds: 3),
  4. bool includeGeo = true,
})

Track an event with Mixpanel including geolocation

Implementation

Future<void> trackEvent(
  String eventName, {
  Map<String, dynamic>? properties,
  Duration timeout = const Duration(seconds: 3),
  bool includeGeo = true,
}) async {
  try {
    final userId = _generateUserId();

    // Get geolocation data
    var geoData = <String, dynamic>{};
    if (includeGeo) {
      try {
        geoData = await _getGeolocationData();
      } catch (e) {
        // Don't fail the event if geo lookup fails
        log('Geolocation lookup failed (non-critical): $e');
      }
    }

    final eventData = {
      'event': eventName,
      'properties': {
        'token': _mixpanelToken,
        'distinct_id': userId,
        'time': DateTime.now().millisecondsSinceEpoch,
        r'$insert_id':
            '${userId}_${eventName}_${DateTime.now().millisecondsSinceEpoch}',

        // Add CLI-specific properties
        'cli_version': Platform.version,
        'platform': Platform.operatingSystem,
        'platform_version': Platform.operatingSystemVersion,

        // Add geolocation properties with $ prefix for Mixpanel's built-in properties
        if (geoData.isNotEmpty) ...{
          r'$city': geoData['city'],
          r'$region': geoData['region'],
          r'$country_code': geoData['country_code'],
          'country': geoData['country'],
          'timezone': geoData['timezone'],
          'isp': geoData['isp'] ?? geoData['org'],
          'geo_service': geoData['service_used'],
        },

        // Add custom properties
        if (properties != null) ...properties,
      },
    };

    final encodedData = base64Encode(utf8.encode(json.encode(eventData)));

    final response = await _httpClient
        .post(
          Uri.parse(_mixpanelUrl),
          headers: {'Content-Type': 'application/x-www-form-urlencoded'},
          body: 'data=$encodedData',
        )
        .timeout(timeout);

    // Mixpanel returns "1" for success
    if (response.statusCode == 200 && response.body == '1') {
      // Success - event tracked
      return;
    } else {
      // Log error but don't fail the command
      log(
        'Mixpanel tracking failed: ${response.statusCode} - ${response.body}',
      );
    }
  } catch (e) {
    // Silently fail - don't let analytics break the CLI
    log('Analytics error (non-critical): $e');
  }
}