Custom Events

Track user activity and conversions in your Airship channels, submit external events to Airship, trigger messages and journeys, and segment your audience with custom events.

Overview

Custom events extend our default events. Such events as opens or tag change are applicable to all apps and websites. Custom events, on the other hand, are specific to the needs of your app or website. For example, you may be interested in tracking the order created event in your e-commerce app, the playback started event in your content delivery platform, or the OnParticipatedInExperimentNotification event in your A/B testing application for tracking user participation.

You may track custom events either via our mobile and web SDKs or by using any other event tracking system.

 Note

If you are already using Google Analytics, we provide iOS and Android SDK extensions that proxy Google Analytics events as Airship custom events. To learn more, see iOS Custom Events, Android Custom Events, and our GA Tracker repos on Github:

In this guide, we will show you how to tie your digital engagement activities together using custom events:

Set up via templates or directly in code
Setting up a custom event for your app is easy. For common event types, we provide ready-made templates in our iOS, Android, and Web SDKs. Alternatively, you can set up custom events directly in your code by instantiating a class from the SDK that implements the custom event API and passing a string that represents the name of the event.
Extend with properties
To provide more detail and customization to the events you are tracking, you may make use of event properties. These are key/value pairs, where the key represents the name of a property and the value is the information associated with this property. Examples of event properties are a product SKU on a purchase event, or a category on a viewed video event.
Stream in real time
Our Real-Time Data Streaming supports streaming custom events to your business systems in real time. See our Data Streaming API Reference for details.
Trigger automation or journey
You may set up custom events and their properties to trigger an automation or journey: members of your audience may receive personalized messages with dynamic content (handlebars)Handlebars is Airship’s templating language for personalization. Handlebars expressions use double curly braces wrapped around a content template, ranging from a simple variable, e.g., {{first_name}} to complex evaluations of personalization data. that includes information from the custom event.

For example, if your custom event has a user_name property, you can add {{user_name}} to your message, and anybody receiving the message would see their user name — the value of the user_name property.

Tracking Custom Events

We recommend starting by identifying a few most important actions that users perform in your app or site. These could include:

  • Registering for an account
  • Using a new feature
  • Watching a video
  • Viewing a specific screen
  • Saving or sharing content
  • Adding a product to a list or cart
  • Making a purchase

Custom events track actions and not objects. For this reason, a good practice is to apply the verb-first naming convention to custom events.

You can also track these events in varying levels of detail, based on how you name them, and optionally include values with each event. You may have other systems that track the granular specifics of your e-commerce engine or content consumption. To measure the impact of push, consider keeping reports at a higher level when starting out. For example, as a publisher, you could track a purchase event in a few ways:

  • Purchased a Magazine
  • Purchased a Sports Magazine
  • Purchased Sports Illustrated, Volume 17, Issue 9

While the third variation above might provide the most detail, you can start with the first level of granularity to keep your reports easy to digest and roll-up, and still see which push notifications were driving the most engagement or ROI.

Here are some examples in more detail:

 Tip

In our examples below, event names are lowercased. We use dashes to separate levels of granularity, and underscores for multi-word names/values. For example:

  • event_name-event_category
  • purchased_item-sports_magazine

Market VerticalDescriptionExample Event NameEvent Value
AllUser registers for an accountregistered_account
AllUser stars any product, article, or contentstarred_content
MediaUser browses a category articles or contentbrowsed_content
MediaUser plays a video Could use the event value to set the amount of time spent watching the video. Report the event after the user navigates away from the video or stops the video.consumed_contentPercentage of content consumed
MediaUser shares contentshared_content
RetailUser adds item to cartadded_to_cart
RetailUser purchases an item Use event value to capture the value of the itempurchasedPurchase Price

We provide ready-made templates for our mobile and web SDKs to get you started with a number of common account-, media-, and retail-related events. To browse the available templates, see Custom Event Templates.

With our mobile and web SDKs, tracking custom events is similar to adding an Airship segmentation tag. Set specific properties and assign a range of values that must be met in order to trigger automation rules. Custom event properties can contain objects and arrays of objects. Use dot notation to access nested properties: parent_property.child_property.

 Note

Custom event properties used to be referenced in the $data.events.[0].properties namespace. If you have templates referencing properties in this namespace, they’ll still work, but you’ll have to continue using this namespace until you contact Airship and move over to the simplified namespace for custom event properties.

To minimize battery consumption, custom events are automatically combined and sent batched in the background. For more information, see Appendix: Code Samples.

Simple example
Here is a simple example that demonstrates how to track a custom event named consumed_content:

iOS

  let event = UACustomEvent(name: "consumed_content", value: 123.12)

  // Set custom event properties
  var propertyDictionary = Dictionary <String, Any>()
  propertyDictionary["boolean_property"] = true
  propertyDictionary["string_property"] = "string_value"
  propertyDictionary["number_property"] = 11
  event.properties = propertyDictionary
  
  // Record the event in analytics
  event.track()
  
  // Create and name a custom event
  UACustomEvent *event = [UACustomEvent eventWithName:@"consumed_content"];
  
  // Set properties
  NSMutableDictionary<NSString *, id> *propertyDictionary = [NSMutableDictionary dictionary];
  [propertyDictionary setValue:@YES forKey:@"boolean_property"];
  [propertyDictionary setValue:@"string_value" forKey:@"string_property"];
  [propertyDictionary setValue:@11 forKey:@"number_property"];
  event.properties = propertyDictionary;
  
  // Start tracking the event
  [event track];
  

Android

  // Create and name an event
  Builder builder = CustomEvent.newBuilder("consumed_content");
  
  // Set custom event properties on the builder
  builder.addProperty("bool_property", true);
  builder.addProperty("string_property", "string_property_value");
  builder.addProperty("int_property", 11);
  builder.addProperty("double_property", 11.0d);
  builder.addProperty("long_property", 11L);
  
  ArrayList<String> collection = new ArrayList<String>();
  collection.add("string_array_value_1");
  collection.add("string_array_value_2");
  collection.add("string_array_value_3");
  builder.addProperty("collection_property", JsonValue.wrapOpt(collection));
  
  CustomEvent event = builder.build();
  
  // Start tracking the event
  event.track();
  

Web

  // Create and name an event
  var event = new sdk.CustomEvent("consumed_content")
  
  // Start tracking the event
  event.track()
  
Assigning a value to a custom event
In this example, you will create an event with a value for advanced analytics reporting:

iOS

  // Create and name an event with a value
  UACustomEvent *event = [UACustomEvent eventWithName:@"event_name" value:@123.12];
  
  // Start tracking the event
  [event track];
  

Android

  // Create and name a simple event - and with a value
  CustomEvent event = new CustomEvent.Builder("event_name")
        .setEventValue(123.12)
        .create();
  
  // Record the event
  UAirship.shared().getAnalytics().addEvent(event);
  

Web

  // Create and name an event with a value
  var event = new sdk.CustomEvent('event_name', 123.12)
  
  // Start tracking the event
  event.track()
  

Server-Side Events

Server-side events are sent through the Custom Events API. When you submit an event, you’ll provide the channel IDAn Airship-specific unique identifier used to address a channel instance, e.g., a smartphone, web browser, email address. or Named User IDA customer-provided identifier used for mapping multiple devices and channels to a specific individual. of the user you want to associate the event with.

You can use Custom Event Triggers to send automated messages to the channel ID or named user associated with each event. Attributing events to named users can help you better represent user actions and trigger automations for individual users without having to map channels to external IDs. Server-side events are involved in a significant number of Airship integrations.

 Note

Server-side events cannot be used to trigger an In-App Automation.

Sample Custom Event

[
   {
      "occurred": "2016-05-02T02:31:22",
      "user": {
         "named_user_id": "hugh.manbeing"
      },
      "body": {
         "name": "purchased",
         "value": 239.85,
         "transaction": "886f53d4-3e0f-46d7-930e-c2792dac6e0a",
         "interaction_id": "your.store/us/en_us/pd/shoe/pid-11046546/pgid-10978234",
         "interaction_type": "url",
         "properties": {
            "description": "Sneaker purchase",
            "brand": "Victory Sneakers",
            "colors": [
             "red",
             "blue"
            ],
            "items": [
               {
                  "text": "New Line Sneakers",
                  "price": "$ 79.95"
               },
               {
                  "text": "Old Line Sneakers",
                  "price": "$ 79.95"
               },
               {
                  "text": "Blue Line Sneakers",
                  "price": "$ 79.95"
               }
            ],
            "name": "Hugh Manbeing",
            "userLocation": {
               "state": "CO",
               "zip": "80202"
            }
         },
         "session_id": "22404b07-3f8f-4e42-a4ff-a996c18fa9f1"
      }
   }
]

Custom Events vs. Audience Segmentation Tags

Custom events are similar to audience segmentation tags. While tags target users via audience segmentation, custom events inform analytics reporting and trigger automated messages.

For example, a user can be tagged as a purchaser after making a purchase. This user can be segmented later for sending follow-up messages. You may use a custom event to track when the user purchased shoes. This is something that happened, and you may wish to calculate its business impact across all users.

Audience tags are useful to identify users for future campaigns. A person who has purchased before may be receptive to a different type of future messaging. A tag only tells you that this user purchased at least once. Because it is useful to understand how many purchases are made in total during a period of time, we have custom events so you can keep track of both types of data.

Event Reporting

Once you have the latest SDK installed and a snippet of code tracking custom events, you’ll start to see event data show up in your Message Reports.

These events will appear in each message report, and in an aggregate app report, with information on whether each event occurred on an Airship delivery channel (Landing Page or Message Center), or in a custom location in your app or website.

These reports display summary data, and a CSV export option will provide full data that you can manipulate as needed or import into business intelligence or analytics tools.

See View Attributed Events for detail.

Push Attribution

Because Airship has visibility into both the sending and receiving (via SDK) of each push, our Push Attribution model ties these custom events back to each message so that you can see the full story of conversions following both direct and indirect opens.

We track how each custom event is attributed to a specific push. The following options are available:

  • Direct Attribution of Events
  • Indirect Attribution of Events
  • Unattributed Events
Direct attribution
If a push notification is sent to a device and the user taps on the notification to open the app and complete a custom event, then the event will be recorded with the Direct attribution to that push notification.
Indirect attribution
If a push notification is sent to the device and the user does not tap on the notification, but opens the app later that day (within a 12 hour attribution window) and completes a custom event it will be recorded with Indirect attribution to that push notification. If the event is completed after 12 outside of the attribution window, then the event will be categorized as Unattributed.
Unattributed events
If a user completes a custom event during a time when no push was sent, or that user is opted-out, then the event will be categorized as Unattributed.

Appendix: Code Samples

 Tip

When setting up custom events, remember:

  • Start by tracking two to five key activities or conversion points in your app.
  • When naming events, keep the total number of unique event names reasonable, so your reports are easy to read.
  • Event will be ignored if their names contain more than 255 characters.
  • Use consistent naming conventions for your events. We lowercase all incoming events for consistency in reports.
  • Event Values must be between -231 and [231 - 1], or the value will be ignored.
  • Event Values cannot contain $ or , characters, or the value will be ignored (decimals only).

JavaScript for Rich Pages

Send a Message Center page or landing page with the following HTML to set a custom event on the button. In the example below, we create a button (named buy-button) which fires the “bought book” event with a value of 10.99.

<html>
    <head>
        <title>Store</title>
        <script>
            document.addEventListener('ualibraryready', onUAReady)

            function onUAReady() {
              // Name buttons below
              // The output variable is used for debugging - comment out if needed
              var buy_button = document.querySelector('[name=buy-button]')
                , output = document.querySelector('[name=ua-attributes]')

              // For debugging - can be commented out
              // Write all the results of all getters
              output.innerHTML += 'ATTRIBUTES \n'
              output.innerHTML += '---------- \n'
              output.innerHTML += 'User Id:' + UAirship.getUserId() +
               '\n Device Model: ' + UAirship.getDeviceModel() +
               '\n Message Id: ' + UAirship.getMessageId() +
               '\n Message Title: ' + UAirship.getMessageTitle() +
               '\n Message Sent Date: ' + UAirship.getMessageSentDate() +
               '\n Message Sent Date MS: ' + UAirship.getMessageSentDateMS() +
               '\n\n'

              // Enable buttons once the ualibrary is up and running on the page
              buy_button.disabled = false

              // Listen for taps/clicks
              buy_button.addEventListener('click', onclick)
            }

            function onclick(ev) {
              // The output variable is used for debugging - comment out if needed
              var output = document.querySelector('[name=ua-custom-event-info]')
                , message_id = UAirship.getMessageId()

              var custom_event_object = {}
                , el = ev.currentTarget

              // get value and name from the element
              custom_event_object.event_value = el.getAttribute('data-event-value')
              custom_event_object.event_name = el.getAttribute('data-event-name')

              if(!UAirship.getMessageId()) {
                 // If we can't get a messageId, then we must be in a web
                 // view, which, in this case, implies we are on a landing
                 // page.

                 custom_event_object.interaction_type = 'ua_landing_page'
                 custom_event_object.interaction_id = '' + window.location
              }

              // For debugging - can be commented out
              output.innerHTML += 'Sending Event: \n' +
                JSON.stringify(custom_event_object, null, 4) + '\n'

              //Send the event to the SDK
              UAirship.runAction('add_custom_event_action', custom_event_object, ready)

              function ready(error, result) {
                if(error) {
                  // For debugging - can be commented out
                  output.innerHTML += 'Woops! ' +
                    error.message + '\n'

                  return
                }
                // For debugging - can be commented out
                output.innerHTML += 'Success! The server responded:\n' +
                   JSON.stringify(result, null, 4) + '\n'
              }
            }
        </script>
    </head>
    <body>
       <!-- CUSTOMIZE EVENT DATA FOR BUTTON js is looking for data-event-name and data-event-value -->
      <button name="buy-button" data-event-name="clicked_button-Buy_Now" data-event-value="10.99" disabled>
          Buy Now
      </button>
      <!-- START EVENT DATA OUTPUT FOR DEBUGGING COMMENT OUT IF NEEDED-->
      <pre name="ua-attributes">
      </pre>
      <pre name="ua-custom-event-info">
      </pre>
      <!-- END EVENT DATA OUTPUT FOR DEBUGGING -->
    </body>
</html>

Our example detects if a page is a landing page, sets the interaction_type and interaction_id if needed, emits an event to the Custom Events system, and writes debugging information to the DOM.

Under the hood, a landing page is simply a web view, so in order to propagate the knowledge that the event was fired from a landing page to the custom events system, we must set the interaction_type to ua_landing_page and the interaction_id to the URL of the landing page.

For a Message Center page, the UA SDK is able to detect that the event is fired from a Message Center page so interaction_type and the interaction_id will be taken care of by the SDK.

Injecting the Airship JavaScript Interface

If you have a WebView that exists outside of a Message Center you can use the following example to inject the Airship JavaScript interface in to your WebView to be able to send custom events.

 Important

The Airship JavaScript interface runs Airship actions and exposes information about the application. It should only be loaded in WebViews that are displaying content from trusted sources and that only link to other trusted sources.

iOS

The Airship JavaScript interface can be added to any WKWebView whose navigation delegate is an instance of UANativeBridge. Custom WebViews can also implement the UANativeBridgeExtensionDelegate and UANativeBridgeDelegate protocols to extend the JavaScript environment or respond to SDK-defined JavaScript commands.

self.nativeBridge = [UANativeBridge nativeBridge];
self.nativeBridgeExtension = [[UAMessageCenterNativeBridgeExtension alloc] init];

self.nativeBridge.nativeBridgeExtensionDelegate = self.nativeBridgeExtension;
self.nativeBridge.nativeBridgeDelegate = self;
self.nativeBridge.forwardNavigationDelegate = self;
self.nativeBridge = UANativeBridge()
self.nativeBridgeExtension = UAMessageCenterNativeBridgeExtension()

self.nativeBridge.nativeBridgeExtensionDelegate = self.nativeBridgeExtension
self.nativeBridge.nativeBridgeDelegate = self
self.nativeBridge.forwardNavigationDelegate = self

Make sure to remove the delegate when the controller is being deallocated:

- (void)dealloc {
    self.webview.navigationDelegate = nil;
}
deint {
    self.webView.navigationDelegate = nil
}

Optionally, enable UAirship.close() by having the controller implement the close method in the UANativeBridgeDelegate protocol:

- (void)close {
    // Close the current window
}
func close() {
  // Close the current window
}

Allow List Rules

An allow list rule needs to be added for any URL that is not hosted by Airship:

[[UAirship shared].URLAllowList addEntry:@"https://*.yourdomain.com"];
UAirship.shared().urlAllowList.addEntry("https://*.yourdomain.com")

Allow list rules can also be defined in AirshipConfig.plist:

<key>URLAllowList</key>
<array>
        <string>https://*.yourdomain.com</string>
</array>

See UAURLAllowList for more details on creating valid URL patterns.

Android and Amazon

The Airship JavaScript interface can be added to any web view as long as JavaScript is enabled and the client is set to an instance of UAWebViewClient.

webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new UAWebViewClient())

Allow List Rules

Add an allow list rule for any URL that is not hosted by Airship:

UAirship.shared().getUrlAllowList().addEntry("https://*.yourdomain.com");

Alternatively, define the allow list rule in airshipconfig.properties:

urlAllowList = https://*.yourdomain.com

See UrlAllowList for more details on creating valid URL patterns.