Custom Events

Declare your own business events in the Console, send them from your app or from a Screen, trigger campaigns with them and measure them as KPIs.

📘

Availability

Custom Events are available from version 6.2.0 of the Purchasely SDK on iOS, Android, React Native, Flutter and Cordova. An older SDK sends no Custom Event and ignores the campaigns and the Screen actions that use them.

A Custom Event is a business event of your app, for example ARTICLE_READ, ARTICLE_SHARED or CHECKOUT_STARTED. With Custom Events, you can:

  • Trigger a campaign when the event fires, and filter on the properties of the event.
  • Send the event from a Screen with the Track event action, without app code.
  • Measure the event as the primary KPI of an experiment.

This page uses one example from start to end: a news app sends ARTICLE_READ when the user reads an article, and ARTICLE_SHARED when the user shares it.

1. Declare the event properties

A property is a value that an event sends, for example the id of the article. You declare a property once for the app. Then you link it to each event that sends it. Two events can use the same property.

Open Targeting > Events in the Purchasely Console and select the Properties tab.

  1. Type the name of the property.

  2. Select its type: string, int, float, bool, date or array of strings.

  3. Click Add.

    The Properties tab, with the list of property types

The Events column shows the events that use each property. In this example, category is shared by ARTICLE_READ and ARTICLE_SHARED.

The Properties tab: category is linked to two events

🚧

A change to a property applies to every event

A property is shared by all the events of the app. When you rename, retype or delete a property in the Properties tab, the change applies to every event that uses it.

2. Create the event

In Targeting > Events, click New Custom Event.

  1. Type the Name of the event. Use the exact name that your app sends. The SDK compares names exactly, case and spaces included: ARTICLE_READ and article_read are two different events.

  2. Optionally, click the color button to select the color of the event in the Console, and add Tags to sort your events.

  3. In Event properties, select Link an existing property... to add a property that you declared before.

  4. Click Create.

    Link an existing property to the event

The ARTICLE_READ event with three linked properties

You can also create a new property directly in the event dialog: type its name, select its type and click Add. The Console marks it new, and adds it to the Properties tab when you save the event. In this example, ARTICLE_SHARED reuses category and creates share_channel.

ARTICLE_SHARED reuses category and creates share_channel

The Events tab shows one card for each event.

The Events tab with the ARTICLE_READ and ARTICLE_SHARED cards

🚧

Only declared events are sent

The SDK sends only the event names that are declared in the Console. It ignores an event that is not declared, without an error. A typo in the name in your app code makes the event silent.

3. Send the event from your app

Call emit when the action occurs in your app. Send the properties that you declared for the event:

Purchasely.emit(name: "ARTICLE_READ", properties: [
    "article_id": 42,
    "category": "sport",
    "is_premium": true
])
[Purchasely emitWithName:@"ARTICLE_READ"
              properties:@{@"article_id": @42, @"category": @"sport", @"is_premium": @YES}];
Purchasely.emit("ARTICLE_READ", mapOf(
    "article_id" to 42,
    "category" to "sport",
    "is_premium" to true
))
Map<String, Object> properties = new HashMap<>();
properties.put("article_id", 42);
properties.put("category", "sport");
properties.put("is_premium", true);
Purchasely.emit("ARTICLE_READ", properties);
Purchasely.emit('ARTICLE_READ', {
  article_id: 42,
  category: 'sport',
  is_premium: true,
});
await Purchasely.emit('ARTICLE_READ', {
  'article_id': 42,
  'category': 'sport',
  'is_premium': true,
});
Purchasely.emit('ARTICLE_READ', {
  article_id: 42,
  category: 'sport',
  is_premium: true
});

The native call returns immediately and never throws. You can call emit before start().

On Cordova, you can give a success callback and an error callback as the third and fourth arguments. Both are optional.

Properties

  • The name and the property keys are sent as given: no case change and no trim.
  • Supported types are numbers, booleans, strings, dates and lists of strings. On Android: Int, Long, Float, Double, Boolean, String, Date and a list of String.
  • Dates are sent as ISO 8601 strings. On React Native, Flutter and Cordova, pass a date as an ISO 8601 string. On Flutter, a DateTime or any value that the platform channel cannot encode makes the call fail.
  • On React Native, Flutter and Cordova, the bridge checks no property type. The backend casts each value to the type that you declare in the Console.
  • On iOS and Android, the SDK drops a value that it cannot send, such as NaN or a custom object, and logs a warning. It sends the rest of the event normally. This does not apply to Flutter: see the previous bullets.

What the event carries

Each event carries your custom user attributes and the built-in attributes, as they were at the moment of the call.

Consent

When the user refuses the analytics data processing purpose, the SDK sends no new Custom Events.

Separate from the SDK events

Custom Events have their own queue and their own retries. They never reach your PLYEventDelegate (iOS), your EventListener (Android) or the event listener of your React Native, Flutter or Cordova app. The UI/SDK events of Purchasely keep their content and their delivery.

⚠️

Android: exhaustive when on PLYEvent

PLYEvent has a new internal subclass for Custom Events. If your Kotlin code uses when (event) on PLYEvent without an else branch, add an else branch.

4. Trigger a campaign with the event

There are two ways to start:

  • On the card of the event, in Targeting > Events, click Map with a new campaign. The Console opens a new campaign with the event already selected as the trigger.
  • In a campaign, turn on the When section and select the event in Trigger.

The Trigger list contains APP_STARTED, the SDK events that can be triggers, and your Custom Events. You can select more than one event: the campaign starts when one of them fires.

The Trigger list of a campaign, with ARTICLE_READ selected

Filter on the properties

Under Filters, click Filter on properties to start the campaign only when the properties of the event match. Each condition has a Property, an Operation and, for most operations, a value.

  • Click AND/OR to add a condition to the group, then select AND or OR between the conditions.
  • Click Add condition group to add a group of conditions.

In this example, the campaign starts when the user reads a premium article of the sport category:

Filters: is_premium is true AND category equals to sport

The operations depend on the type of the property:

TypeOperations
stringequals to, is different from, contains, starts with, ends with, is one of
intequals to, is different from, is greater than, is greater than or equal to, is less than, is less than or equal to, is between
boolis true, is false, is true or not set, is false or not set

Rules of the trigger

The same rules as for an APP_STARTED trigger apply:

  • The start and end dates of the campaign
  • The frequency cap, the impression cap and the exposure window
  • The campaigns data processing purpose
  • allowCampaigns: when it is false, the SDK keeps the campaign until your app sets it to true again

A Custom Event never opens the campaigns of a Purchasely event that has the same name.

5. Send the event from a Screen

The Track event action of the Screen Composer sends one of your Custom Events when the user taps a component. You do not need app code for this action.

  1. In the Screen Composer, select the component, for example a button.
  2. In On tap > Action, select Track event.

The Track event action in the Action list

  1. In Custom event, select the event.

Select the custom event of the Track event action

  1. Optionally, select a Second action, for example Close/Back.

A Learn More button that sends ARTICLE_READ and then closes the Screen


The event carries the context of the Screen: presentation, placement, audience, A/B test and variant, campaign, and flow and step. You do not set property values in the action.

  • Your app cannot intercept this action.
  • This action never blocks the actions next to it. A button that tracks an event and then purchases still closes the paywall after the purchase.
  • An SDK older than 6.2 ignores this action and sends nothing.

6. Measure the event in an experiment

When you create an experiment, the Primary KPI step lists your Custom Events under Custom Events. Select one to make it the metric that determines the winner. In this example, the experiment measures the number of shared articles.

The Primary KPI step of an experiment, with ARTICLE_SHARED selected


A Local experiment can also target your Custom Events in its When section, the same way as a campaign trigger. Refer to Measuring experiment impact for more details.

7. Best practices with more than one analytics tool

Most apps send the same events to more than one tool, for example Google Analytics for Firebase, Amplitude, Piano Analytics and Purchasely. These rules keep the events correct in all the tools.

Send each event from one place

Put all the tracking calls in one class of your app. Your screens call this class, and this class sends the event to each tool. Do not put Purchasely.emit calls directly in your screens.

enum AppEvent {
    static let articleRead = "ARTICLE_READ"
    static let articleShared = "ARTICLE_SHARED"
}

enum Tracker {
    static func track(_ name: String, _ properties: [String: Any] = [:]) {
        // Firebase, Amplitude, Piano: call each SDK here
        Purchasely.emit(name: name, properties: properties)
    }
}

Tracker.track(AppEvent.articleRead, ["article_id": 42, "category": "sport"])
object AppEvent {
    const val ARTICLE_READ = "ARTICLE_READ"
    const val ARTICLE_SHARED = "ARTICLE_SHARED"
}

object Tracker {
    fun track(name: String, properties: Map<String, Any> = emptyMap()) {
        // Firebase, Amplitude, Piano: call each SDK here
        Purchasely.emit(name, properties)
    }
}

Tracker.track(AppEvent.ARTICLE_READ, mapOf("article_id" to 42, "category" to "sport"))

With one class, a new tool needs one change only, and no screen forgets a tool.

Use one list of event names

  • Keep the event names as constants, as in the previous example. Purchasely ignores an event name that is not declared, without an error, so a typo makes the event silent.
  • Select names that all your tools accept. For example, a Firebase event name has a maximum of 40 characters, contains only letters, digits and _, starts with a letter, and does not start with firebase_, google_ or ga_. ARTICLE_READ is correct in Firebase and in Purchasely.
  • If a tool needs a different name, change the name for this tool in the tracking class only. Keep one name in your app code.

Use the same properties in all the tools

  • Use the same property keys and the same types in all the tools. In Purchasely, the types must agree with the types that you declare in the Console.
  • Send dates as ISO 8601 strings.
  • Do not send personal data, such as an email address or a name, in the properties.

Declare in Purchasely only the events that you use

Declare in the Console only the events that you need for a campaign trigger, a trigger filter or an experiment KPI. The tracking class can send all the events to Purchasely: the SDK sends only the declared events and ignores the other events.

Do not send a Purchasely SDK event again with emit. The Trigger list of a campaign already contains the SDK events that can be triggers.

Identify the user in all the tools at the same time

  • Call Purchasely.userLogin and Purchasely.userLogout at the same time as the login and logout calls of your other tools. Refer to Identifying users.
  • Set the same user attributes in all the tools.
  • Give the ids of the other tools to Purchasely, for example the Firebase app instance id or the Amplitude device id. Purchasely then attaches its server events to the same user in these tools. Each integration page gives the attribute to set.

Apply the same consent to all the tools

Keep one consent choice in your app, and apply it to all the tools. When the user refuses analytics, revoke the analytics purpose in Purchasely with revokeDataProcessingConsent (refer to Privacy settings), and stop the other tools too. Without the analytics purpose, Purchasely sends no Custom Event.

Count each event one time only

The same action can reach your analytics tool by more than one path:

  • Your tracking class (your own events)
  • The Purchasely UI/SDK events that your event listener sends to your tool
  • The Purchasely server events that an integration sends to your tool, for example a purchase or a renewal

For each event, use one path only. For example, if Purchasely sends the purchase server events to Amplitude, do not also send a purchase event to Amplitude from your app.

Know the limit of the Track event action

The Track event action of a Screen sends the event to Purchasely only. Your app receives no signal: the action does not go to your action interceptor or to your event listener. If you also need this event in another tool, send it from your app with your tracking class, not with this action.



Did this page help you?