Custom Events and Properties

Event Tracking with UXCam

Screens tell you where users go; events show what they do.
With a handful of well‑chosen events (5‑15 is ideal) plus descriptive properties, you can build funnels, spot drop‑offs, and debug support tickets in minutes.


Choose the Right Moments to Track

Event typeWhy tag it?Typical name examples
Flow milestonesBuild conversion funnelsSignup_Started, Signup_Completed
Key feature useMeasure adoptionVideo_Export, AR_Scan
Errors / cancelsQuantify frictionPayment_Failed, Upload_Cancelled
A/B exposureCompare cohortsVariant_Shown_A

Tip: Too many events dilute insight and bloat dashboards—focus on what drives decisions.


Send a Basic Event

FlutterUxcam.logEvent("Signup_Started");

Best‑practice

  • Use PascalCase or snake_case.
  • Store names as constants to prevent typos.
  • Remember that names are case‑sensitive: signup_startedSignup_Started.

Example with Constants:

class EventNames {
  static const String signupStarted = "Signup_Started";
  static const String signupCompleted = "Signup_Completed";
  static const String paymentSucceeded = "Payment_Succeeded";
  static const String videoExport = "Video_Export";
}

// Usage
FlutterUxcam.logEvent(EventNames.signupStarted);

Add Context with Properties

Attach up to 20 key‑value pairs to any event for richer analysis.

Map<String, dynamic> properties = {
  'plan': 'pro',
  'source': 'google_ads',
  'price_cents': 1499,
  'user_type': 'premium',
};

FlutterUxcam.logEvent("Payment_Succeeded", properties);
RuleReason
Keys are case‑sensitivePlan and plan create separate properties.
Values must be String, Number, or BooleanSerialize complex objects to JSON if needed.
Avoid PIIUse hashed values or IDs to stay GDPR‑safe.
Stop at 20 propertiesExtras are discarded and a warning is logged.

Complex Object Example:

class Product {
  final String id;
  final String name;
  final double price;

  Product({required this.id, required this.name, required this.price});

  Map<String, dynamic> toEventProperties() {
    return {
      'product_id': id,
      'product_name': name,
      'price': price,
    };
  }
}

// Usage
final product = Product(id: '123', name: 'Premium Plan', price: 29.99);
FlutterUxcam.logEvent("Product_Viewed", product.toEventProperties());

Automatic Events (No Code Needed)

Auto eventFires when …
Rage TapUser taps ≥ 3 times within 300 ms at the same coordinates
UI FreezeMain thread blocked for ≥ 2 s

Combine these with your custom events for a complete picture of the user experience. You can find more details about Rage Tap and UI Freeze in the UXCam Help Center.


Flutter-Specific Examples

Navigation Events

// Track screen navigation
void onScreenChanged(String screenName) {
  FlutterUxcam.logEvent("Screen_Viewed", {
    'screen_name': screenName,
    'timestamp': DateTime.now().toIso8601String(),
  });
}

User Interaction Events

// Track button taps
void onButtonTapped(String buttonName) {
  FlutterUxcam.logEvent("Button_Tapped", {
    'button_name': buttonName,
    'screen': ModalRoute.of(context)?.settings.name ?? 'unknown',
  });
}

Form Events

// Track form interactions
void onFormSubmitted(String formName, Map<String, dynamic> formData) {
  FlutterUxcam.logEvent("Form_Submitted", {
    'form_name': formName,
    'field_count': formData.length,
    'has_errors': formData.values.any((value) => value == null),
  });
}

Verify Your Events

  1. Trigger the event in a debug build and wait for upload.
  2. Open Dashboard → Events.
  3. Confirm the new event and its properties appear.
  4. Play a session replay—the event pin should align with the exact moment.

Testing Example:

// Add this to your debug builds for testing
void testEventLogging() {
  FlutterUxcam.logEvent("Test_Event", {
    'test_property': 'test_value',
    'timestamp': DateTime.now().toIso8601String(),
  });
}

Troubleshooting Cheat‑Sheet

IssueLikely causeFix
Event missingName typo or the event was logged before the SDK was initializedUse constants; ensure the event is logged only after FlutterUxcam.startWithConfiguration() has been called.
Property not shownSent > 20 propsTrim to 20; bundle extras in one JSON string
Duplicate eventsCalled inside loops / retriesAdd guards (e.g., send once per session)
Mixed‑case duplicatesSignup_started vs Signup_StartedStandardise naming casing

Example Guard Implementation:

class EventGuard {
  static final Set<String> _sentEvents = {};

  static void logEventOnce(String eventName, [Map<String, dynamic>? properties]) {
    if (!_sentEvents.contains(eventName)) {
      FlutterUxcam.logEvent(eventName, properties);
      _sentEvents.add(eventName);
    }
  }

  static void reset() {
    _sentEvents.clear();
  }
}

QA Checklist

  • All custom events appear in the Events dashboard and on session replays.
  • Properties display correct values, types, and casing.
  • No unwanted duplicates (case or spelling).
  • Event pins align with the correct second in replay.
  • No PII present in names or properties.
  • Events are logged only after SDK initialization.
  • Property count stays under 20 per event.

By leveraging events and properties effectively, you can unlock valuable insights into how users interact with your app, leading to better product decisions and enhanced user experiences.