Skip to main content
Event tracking is used to track user behavior in an app. And later based on the same tracked behavior you can target those users for sending relevant notifications. Make sure to track all the events relevant to your business, so that your product managers and marketers can segment your app users and create targeted campaigns. For eg. You can track what a user is purchasing, whether has a user added an item to the cart etc.
  • We track certain events by default in our SDK, so please make sure to use the default events instead of tracking a new event for the same scenarios. Find the list of default events tracked by SDK here.
  • SDK adheres to the MoEngage FUP policies. For more information, refer to the Fair Usage Policy.

How to track events?

Every event has 2 parts to it, the “name” of the event and the properties/attributes of the event. You have to make use of MoEngageProperties to track events and their attributes. For eg. The following code tracks a Successful Purchase event. We are including attributes like the Product Name, a Brand Name that describes the event we are tracking.
var eventAttrDict : Dictionary<String,Any> = Dictionary()
eventAttrDict["ProductName"] = "iPhone XS Max"
eventAttrDict["BrandName"] = "Apple"
eventAttrDict["Items In Stock"] = 109

let eventProperties = MoEngageProperties(withAttributes: eventAttrDict)

eventProperties.addAttribute(87000.00, withName: "price")
eventProperties.addAttribute("Rupees", withName: "currency")
eventProperties.addAttribute(true, withName: "in_stock")
eventProperties.addDateEpochAttribute(1439322197, withName: "Time added to cart")
eventProperties.addDateISOStringAttribute("2020-02-22T12:37:56Z", withName: "Time of checkout")
eventProperties.addDateAttribute(Date(), withName: "Time of purchase")

eventProperties.addLocationAttribute(MoEngageGeoLocation.init(withLatitude: 12.23, andLongitude: 9.23), withName: "Pickup Location")

/// JSON is supported from MoEngage-iOS-SDK v9.17.5
eventProperties.addAttribute(["merchantId": "abcdef","business_model": [ "admin_email": "[email protected]","admin_comment": "payment" ]],withName: "merchant")
<br>
eventProperties.addAttribute([["merchantId": "abcdef", "business_model": ["admin_email": "[email protected]", "admin_comment": "first"]], ["merchantId": "ghijk", "business_model": ["admin_email": "[email protected]", "admin_comment": "second"]]], withName: "retries")
      
MoEngageSDKAnalytics.sharedInstance.trackEvent("Successful Purchase", withProperties: eventProperties)
Non-Interactive EventsEvents that should not affect the session duration calculation in anyways in MoEngage Analytics should be marked as a Non-Interactive events. Refer to this for more info on the same.
If you don’t have any attributes, just pass nil as the second argument. For eg.
MoEngageSDKAnalytics.sharedInstance.trackEvent("Event Name", withProperties: nil)

Validations and restrictions

Event attributes have two layers of validation that apply across both DEBUG and release builds:
  • Naming and format rules — these always apply, regardless of build configuration. Refer to Naming and format rules below.
  • Type validation — invalid attribute values (unsupported types such as null, custom models, NaN, Infinity, empty collections, or Date/MoEngageGeoLocation nested inside an Array or Dictionary) cause a fatal exception in DEBUG builds and are silently dropped from the payload in release builds. The rest of the event is tracked. Refer to Supported attribute value types below.
In the iOS SDK, DEBUG mode means the SDK was initialized using initializeDefaultTestInstance(_:) (TEST workspace) and the app is running attached to Xcode. This is different from a release build that has debug symbols enabled.

Naming and format rules

  • Attribute names must be non-empty. Passing an empty string ("") as an attribute name causes a fatal exception in DEBUG builds. In release builds, the attribute is dropped.
  • Reserved prefixes. You cannot use moe_ as a prefix when naming events, event attributes, or user attributes. It is a system prefix, and using it might result in periodic blocklisting without prior communication.

Supported attribute value types

Attribute values must be one of: String, Number, Date, MoEngageGeoLocation, Dictionary (with string keys and supported values), or Array (of supported values). If an unsupported value is passed:
  • In DEBUG builds, the SDK throws a fatal exception and crashes the app to surface data issues early in development.
  • In Release and TestFlight builds, the SDK silently drops the specific invalid attribute and logs the issue. The rest of the event payload is still tracked.
Common triggers for the DEBUG exception:
  • Passing null (NSNull()).
  • Passing custom models or UI elements (for example, UIColor, UIImage).
  • Passing invalid numbers like NaN or Infinity.
  • Passing empty Arrays or Dictionaries.
  • Nesting Date or MoEngageGeoLocation objects inside an Array or Dictionary. These must be passed directly as values.
If you are upgrading an existing app and these strict DEBUG validations cause disruptive crashes while you refactor your tracking code, you can temporarily opt out by calling disableIntegrationValidator() during SDK initialization. Use this strictly as a stopgap for phased upgrades, and aim to remove the opt-out once your attribute call sites are properly validated.

Filtering unsupported attribute values

If you are upgrading to a newer version of the iOS SDK and your app passes attribute values whose types are not validated at the call site, add a type-check guard before building the MoEngageProperties object. This prevents DEBUG crashes and ensures only valid data reaches the SDK in all builds.
// Helper to check if a value is a supported event attribute type.
  // Call this before passing any dynamically-typed value to addAttribute(_:withName:).
  func isSupportedEventAttributeValue(_ value: Any) -> Bool {
      switch value {
      case let d as Double: return !d.isNaN && !d.isInfinite
      case let f as Float:  return !f.isNaN && !f.isInfinite
      case is String, is Bool, is Int, is Int8, is Int16, is Int32, is Int64,
           is UInt, is UInt8, is UInt16, is UInt32, is UInt64, is NSNumber:
          return true
      case let arr as [Any]:        return !arr.isEmpty
      case let dict as [String: Any]: return !dict.isEmpty
      default: return false
      }
  }

  // Usage — value comes from a server response, external model, or unknown source
  let properties = MoEngageProperties()
  if isSupportedEventAttributeValue(dynamicValue) {
      properties.addAttribute(dynamicValue, withName: "attribute_name")
  }

Date and MoEngageGeoLocation values must be passed using the dedicated addDateAttribute, addDateEpochAttribute, addDateISOStringAttribute, and addLocationAttribute methods — not through the dictionary-based withAttributes: initializer or addAttribute:withName:.

Manual Sync

For syncing the tracked events instantaneously, use the flush() method as shown below:
MoEngageSDKAnalytics.sharedInstance.flush()

Testing events after integration

Login to the MoEngage account with the credentials provided for your app. Look at the top left and Switch to the Test environment. Ensure that your testing is done on the test environment to keep the test data separate from the Live data. Ensure you have Initialized the SDK. After adding event tracking in the app, as shown above, you can visit Dashboard > Recent Events to check whether the events are being tracked. Events can take up to 20 minutes to show up in the dashboard While testing it is recommended to enable logs in Debug Mode. SDK prints a list of all events which are synced in the current flush, so you can always refer to the logs to check if the events tracked by you are being sent to the backend or not. Also, logs provide info about if the sync with the backend was successful or not. (In case it is unsuccessful, SDK saves all the tracked events and attempts to sync again in the next flush attempt).