Event Tracking
GameAnalytics features the following event types:
Event | Description |
---|---|
Ad | Ads shown and clicked, fill rate. |
Business | In-App Purchases supporting receipt validation on GA servers. |
Design | Submit custom event id’s. Useful for tracking metrics specifically needed for your game. |
Error | Submit exception stack traces or custom error messages. |
Health | Automatically submits health metrics related to your game such as FPS. |
Impression | Impression data from different ad networks |
Progression | Level attempts with Start, Fail & Complete event. |
Resource | Managing the flow of virtual currencies - like gems or lives |
Read more about events here
To send an event, remember to include the namespace GameAnalyticsSDK:
using GameAnalyticsSDK;
If you are new to GameAnalytics and our Events, please read our event guide here. You will get the most benefit of GameAnalytics when understanding what and how to track events.
Remember to only send events from main thread as the SDK internally uses some Unity functions which can only be used from main thread.
Business Events
With validation
Receipt validation in Unity is supported for the following stores:
- App Store (iOS)
- Google Play Store (Android)
// Android - Google Play
#if (UNITY_ANDROID)
GameAnalytics.NewBusinessEventGooglePlay (string currency, int amount, string itemType, string itemId, string cartType, string receipt, string signature)
#endif
// iOS - with receipt
#if (UNITY_IOS)
GameAnalytics.NewBusinessEventIOS (string currency, int amount, string itemType, string itemId, string cartType, string receipt)
#endif
// iOS - with autoFetchReceipt
#if (UNITY_IOS)
GameAnalytics.NewBusinessEventIOSAutoFetchReceipt (string currency, int amount, string itemType, string itemId, string cartType)
#endif
Without Validation
It is also possible to send business events without validation.
GameAnalytics.NewBusinessEvent (string currency, int amount, string itemType, string itemId, string cartType)
Field | Type | Description | Example |
---|---|---|---|
currency | string | Currency code in ISO 4217 format | USD |
amount | integer | Amount in cents | 99 is $0.99 |
itemType | string | The type/category of the item | GoldPacks |
itemId | string | Specific item bought | 1000GoldPack |
cartType | string | The game location of the purchase. Max 10 unique values | EndOfLevel |
iOS Only
Field | Type | Description |
---|---|---|
receipt | base64 string | The App Store receipt. Null allowed. Read about App Store receipt here. |
Android Only
Field | Type | Description |
---|---|---|
receipt | string | INAPP_PURCHASE_DATA . Null allowed. Read about Android receipt here |
signature | base64 string | INAPP_DATA_SIGNATURE . Null allowed. Read about Android signature here. |
Android Receipt Contents
This json describes the android receipt sent over to GameAnalytics.
{
"orderId": "<order_id>",
"packageName": "<package_name>",
"productId": "<product_id>",
"purchaseTime": 1484080095335,
"purchaseState": 0,
"purchaseToken": "<purchase_token>"
}
The receipt assigned to the Android business event method should not be base64 encoded. The GameAnalytics Android library will encode the receipt for you.
iOS with AutoFetchReceipt
The method NewBusinessEventIOSAutoFetchReceipt will attempt to locate the latest receipt in iOS native code and submit the event if found Retrieving Receipts with Unity IAP service
The IStoreController
object that you used to initialize the Unity IAP service contains all the products available for purchase declared by you as well as the receipts.
The receipts can be accessed as follows:
private IStoreController controller;
private IExtensionProvider extensions;
//..
public class Receipt {
public string Store;
public string TransactionID;
public string Payload;
public Receipt()
{
Store = TransactionID = Payload = "";
}
public Receipt(string store, string transactionID, string payload)
{
Store = store;
TransactionID = transactionID;
Payload = payload;
}
}
public class PayloadAndroid
{
public string json;
public string signature;
public PayloadAndroid()
{
json = signature = "";
}
public PayloadAndroid(string _json, string _signature)
{
json = _json;
signature = _signature;
}
}
//...
public PurchaseProcessingResult ProcessPurchase (PurchaseEventArgs args)
{
if (String.Equals (args.purchasedProduct.definition.id, kProductIDConsumable, StringComparison.Ordinal)) {
//...
var product = m_StoreController.products.WithID(kProductIDConsumable);
string receipt = product.receipt;
string currency = product.metadata.isoCurrencyCode;
int amount = decimal.ToInt32 (product.metadata.localizedPrice * 100);
#if UNITY_ANDROID
Receipt receiptAndroid = JsonUtility.FromJson<Receipt>(receipt);
PayloadAndroid receiptPayload = JsonUtility.FromJson<PayloadAndroid>(receiptAndroid.Payload);
GameAnalytics.NewBusinessEventGooglePlay(currency, amount, "my_item_type", kProductIDConsumable, "my_cart_type", receiptPayload.json, receiptPayload.signature);
#endif
#if UNITY_IPHONE
Receipt receiptiOS = JsonUtility.FromJson<Receipt> (receipt);
string receiptPayload = receiptiOS.Payload;
GameAnalytics.NewBusinessEventIOS (currency, amount, "my_item_type", kProductIDConsumable, "my_cart_type", receiptPayload);
#endif
}
On iOS you need to send the entire payload while for Android GameAnalytics should receive only the contents of the json field inside the payload. Information about these can be found in the Unity documentation about the receipts.
For parsing the receipt JSON and getting the data listed under the json field we recommend a JSON parser such as JSON Object.
Custom Event Fields
It is possible to use a set of key-value pairs to add extra fields but it will only be available through raw data export. Here is an example of how to use it:
Dictionary<string, object> fields = new Dictionary<string, object>();
fields.put("test", 100);
fields.put("test_2", "hello_world");
GameAnalytics.NewBusinessEventGooglePlay(currency, amount, "my_item_type", kProductIDConsumable, "my_cart_type", receiptPayload.json, receiptPayload.signature, fields);
For more information on custom event fields and raw data export go here.
We do not support purchase validation for any of the other platforms listed by Unity IAP (Mac App store or Windows store).
For more information on Business Events go here.
Ad Events
Ad Events are supported only for the Android and iOS! platforms
The GameAnalytics ad event needs to be called when certain ad events have been triggered. Ad SDKs usually have callback methods for certain events (like when showing an ar or when an ad has been clicked).
To use the ad event it is need to call the GameAnalytics SDK when these delegates are called. The examples below describe how to implement this for the following ad-types:
- rewarded video
- interstitial
- bannner
All code examples use AdMob SDK to showcase example usage.
Other ad networks might differ in naming/structure, but the overall process should be applicable to all.
The ad SDK name argument for the ad event needs to be all lower-case with no spaces or underscore used. Here some examples of valid values to use for ad SDK names:
admob
unityads
ironsource
applovin
Rewarded Videos
Showing a Rewarded video
It is possible that the ad SDK cannot return an ad for your app. You can track if the rewarded video has failed to show with the following event.
if (this.rewardedAd.IsLoaded()) {
// show the ad
this.rewardedAd.Show();
// send ad event
GameAnalytics.NewAdEvent(GAAdAction.Show, GAAdType.RewardedVideo, "admob", "[AD_PLACEMENT_OR_UNIT_ID]");
}
else
{
GameAnalytics.NewAdEvent(GAAdAction.FailedShow, GAAdType.RewardedVideo, "admob", "[AD_PLACEMENT_OR_UNIT_ID]");
}
Track time spent inside the ad
If you want to track how much time it took the user to watch the ad you can start a timer and keep track of current rewarded video ad when OnAdOpening
delegate is called. The following example is a method for how you could handle this.
public void HandleRewardedAdOpening(object sender, EventArgs args)
{
// keep track of current rewarded video ad
currentRewardedVideoPlacement = "[AD_PLACEMENT_OR_UNIT_ID]";
// start timer for this ad identifier
GameAnalytics.StartTimer(currentRewardedVideoPlacement);
}
// when application goes to background (during the display of a rewarded video ad) then the timer needs to stop.
// therefore we need to call code in Unity method OnApplicationPause.
void OnApplicationPause(bool paused) {
if(paused)
{
if(currentRewardedVideoPlacement != null)
{
GameAnalytics.PauseTimer(currentRewardedVideoPlacement);
}
}
else
{
if(currentRewardedVideoPlacement != null)
{
GameAnalytics.ResumeTimer(currentRewardedVideoPlacement);
}
}
}
Track when the ad has finished
It is useful to track when the ad has finished and the user returns to the game. For admob this delegate is called OnAdClosed
and the following example is a method for how you could handle this.
public void HandleRewardedAdClosed(object sender, EventArgs args) {
if(currentRewardedVideoPlacement != null)
{
long elapsedTime = GameAnalytics.StopTimer(currentRewardedVideoPlacement);
// send ad event for tracking elapsedTime
GameAnalytics.NewAdEvent(GAAdAction.Show, GAAdType.RewardedVideo, "admob", "[AD_PLACEMENT_OR_UNIT_ID]", elapsedTime);
currentRewardedVideoPlacement = null;
// OR if you do not wish to track time
// send ad event without tracking elapsedTime
GameAnalytics.NewAdEvent(GAAdAction.Show, GAAdType.RewardedVideo, "admob", "[AD_PLACEMENT_OR_UNIT_ID]");
}
}
Interstitials
Showing an Interstitial ad
As in the example for the rewarded video, you can also send an event when the ad has failed to load.
if (this.interstitial.IsLoaded()) {
// show the ad
this.interstitial.Show();
// send ad event
GameAnalytics.NewAdEvent(GAAdAction.Show, GAAdType.Interstitial,"admob", "[AD_PLACEMENT_OR_UNIT_ID]");
}
else
{
GameAnalytics.NewAdEvent(GAAdAction.FailedShow, GAAdType.Interstitial, "admob", "[AD_PLACEMENT_OR_UNIT_ID]");
}
Closing an Interstitial ad
This event should be called when the interstitial ad has been finished. The equivalent for the admob sdk is OnAdLeavingApplication
.
public void HandleInterstitialLeftApplication(object sender, EventArgs args) {
// send ad event - ad click
GameAnalytics.NewAdEvent(GAAdAction.Clicked, GAAdType.Interstitial,"admob", "[AD_PLACEMENT_OR_UNIT_ID]");
}
Banners
Showing a Banner Ad
It is possible to track when a banner ad has been loaded by using the following event. For admob this callback would be used when OnAdLoaded
is called.
public void HandleAdLoaded(object sender, EventArgs args) {
GameAnalytics.NewAdEvent(GAAdAction.Show, GAAdType.Banner,"admob", "[AD_PLACEMENT_OR_UNIT_ID]");
}
Track banner clicks
If you wish to track when an user is clicking on a banner ad you have to use this event. For admob this should be triggered on OnAdOpening
.
public void HandleAdOpened(object sender, EventArgs args) {
// send ad event
GameAnalytics.NewAdEvent(GAAdAction.Clicked, GAAdType.Banner, "admob", "[AD_PLACEMENT_OR_UNIT_ID]");
}
Custom Banner Event Fields
It is possible to append extra information to this event as a map of key-value pairs.
The custom information will only be available through raw data export!
The sample below will show you how to add custom fields:
Dictionary<string, object> fields = new Dictionary<string, object>();
fields.put("test", 100);
fields.put("test_2", "hello_world");
GameAnalytics.NewAdEvent(GAAdAction.Clicked, GAAdType.Banner, "admob", "[AD_PLACEMENT_OR_UNIT_ID], fields");
}
For more information on custom event fields and raw data export go here.
Ad Event Info
In the table below you can find all the values supported for ad events.
Field | Type | Description | Example |
---|---|---|---|
adAction | enum | A defined enum for ad action (for example clicked). | GAAdAction.Clicked GAAdAction.Show GAAdAction.FailedShow GAAdAction.RewardReceived |
adType | enum | A defined enum for ad type (for example interstitial). | GAAdType.Video GAAdType.RewardedVideo GAAdType.Playable GAAdType.Interstitial GAAdType.OfferWall GAAdType.Banner |
adSdkName | string | Name of the Ad/Ad mediation SDK. | admob |
adPlacement | string | Identifier of ad in the game or the placement of it. | level_complete_ad |
duration | int | Optional. Only used for video ads to track how long the user watched the video for. | 10 |
noAdReason | enum | Optional. Used to track the reason for not being able to show an ad when needed (for example no fill). | GAAdError.Unknown GAAdError.Offline GAAdError.NoFill GAAdError.InternalError GAAdError.InvalidRequest GAAdError.UnableToPrecache |
For more information on Ad Events go here.
Impression Events
Impression events are used to get impression data from different ad networks. Currently the following ad networks are supported:
- Fyber
- IronSource
- TopOn
- MAX
- Aequus
- AdMob
Fyber
To use impression data from Fyber add the following code inside the Start function and the SDK will then automatically send the impression events for you:
void Start ()
{
// ... code
GameAnalyticsILRD.SubscribeFyberImpressions();
}
IronSource
To use impression data from IronSource add the following code inside the Start function and the SDK will then automatically send the impression events for you:
void Start ()
{
// ... code
GameAnalyticsILRD.SubscribeIronSourceImpressions();
}
TopOn
To use impression data from TopOn add the following code inside the Start function and the SDK will then automatically send the impression events for you:
void Start ()
{
// ... code
GameAnalyticsILRD.SubscribeTopOnImpressions();
}
MAX
To use impression data from MAX add the following code inside the Start function and the SDK will then automatically send the impression events for you:
void Start ()
{
// ... code
GameAnalyticsILRD.SubscribeMaxImpressions();
}
Aequus
To use impression data from Aequus add the following code inside the Start function and the SDK will then automatically send the impression events for you:
void Start ()
{
// ... code
GameAnalyticsILRD.SubscribeAequusImpressions();
}
AdMob
To use impression data from AdMob add the following code for each ad you create and the SDK will then automatically send the impression events for you:
// BannerView
bannerView = new BannerView(adUnitId, AdSize.SmartBanner, AdPosition.Top);
GameAnalyticsILRD.SubscribeAdMobImpressions(adUnitId, bannerView);
// InterstitialAd
interstitialAd = new InterstitialAd(adUnitId);
GameAnalyticsILRD.SubscribeAdMobImpressions(adUnitId, interstitialAd);
// RewardedAd
rewardedAd = new RewardedAd(adUnitId);
GameAnalyticsILRD.SubscribeAdMobImpressions(adUnitId, rewardedAd);
// RewardedInterstitialAd
RewardedInterstitialAd.LoadAd(adUnitId, CreateAdRequest(), (rewardedInterstitialAd, error) =>
{
if(error == null)
{
GameAnalyticsILRD.SubscribeAdMobImpressions(adUnitId, rewardedInterstitialAd);
}
});
For more information on Impression Events go here.
Resource Events
To add a resource event call the following function:
GameAnalytics.NewResourceEvent (GA_Resource.GAResourceFlowType flowType, string currency, float amount, string itemType, string itemId)
Field | Type | Required | Description |
---|---|---|---|
flowType | enum | yes | Add (source) or subtract (sink) resource. |
currency | string | yes | One of the available currencies set in GA_Settings (Setup tab).This string can only contain [A-Za-z] characters. |
amount | float | yes | Amount sourced or sunk. |
itemType | string | yes | One of the available item types set in GA_Settings (Setup tab). |
itemId | string | yes | Item id (string max length = 32) |
Be careful to not call the resource event too often! In a game where the user collect coins fairly fast you should not call a Source event on each pickup.
Instead you should count the coins and send a single Source event when the user either completes or fails the level.
Here are some examples and best practices for structuring the events:
GameAnalytics.NewResourceEvent(GA_Resource.GAResourceFlowType.GAResourceFlowTypeSource, “Gems”, 400, “IAP”, “Coins400”);
GameAnalytics.NewResourceEvent(GA_Resource.GAResourceFlowType.GAResourceFlowTypeSink, “Gems”, 400, “Weapons”, “SwordOfFire”);
GameAnalytics.NewResourceEvent(GA_Resource.GAResourceFlowType.GAResourceFlowTypeSink, “Gems”, 100, “Boosters”, “BeamBooster5Pack”);
GameAnalytics.NewResourceEvent(GA_Resource.GAResourceFlowType.GAResourceFlowTypeSource, “BeamBooster”, 5, “Gems”, “BeamBooster5Pack”);
GameAnalytics.NewResourceEvent(GA_Resource.GAResourceFlowType.GAResourceFlowTypeSink, “BeamBooster”, 3, “Gameplay”, “BeamBooster5Pack”);
Custom Resource Event Fields
It is possible to use a set of key-value pairs to add extra fields but it will only be available through raw data export. Here is an example of how to use it:
Dictionary<string, object> fields = new Dictionary<string, object>();
fields.put("test", 100);
fields.put("test_2", "hello_world");
GameAnalytics.NewResourceEvent(GA_Resource.GAResourceFlowType.GAResourceFlowTypeSink, “BeamBooster”, 3, “Gameplay”, “BeamBooster5Pack”, fields);
For more information on custom event fields and raw data export go here.
Progression Events
Progression events are used to track user's progression in the game, for example a new level, high score or dungeon. In the unity sdk you can register such events with the following api:
// Using 1 progression part (01) and no score
GameAnalytics.NewProgressionEvent(GA_Progression.GAProgressionStatus progressionStatus, string progression01)
// Using 1 progression part (01) and score
GameAnalytics.NewProgressionEvent(GA_Progression.GAProgressionStatus progressionStatus, string progression01, int score)
// Using 2 progression parts (01+02) and no score
GameAnalytics.NewProgressionEvent(GA_Progression.GAProgressionStatus progressionStatus, string progression01, string progression02)
// Using 2 progression parts (01+02) and score
GameAnalytics.NewProgressionEvent(GA_Progression.GAProgressionStatus progressionStatus, string progression01, string progression02, int score)
// Using 3 progression parts (01+02+03) and no score
GameAnalytics.NewProgressionEvent(GA_Progression.GAProgressionStatus progressionStatus, string progression01, string progression02, string progression03, int score)
// Using 3 progression parts (01+02+03) and score
GameAnalytics.NewProgressionEvent(GA_Progression.GAProgressionStatus progressionStatus, string progression01, string progression02, string progression03, int score)
The progression event accepts the following parameters:
Field | Type | Required | Description |
---|---|---|---|
progressionStatus | enum | yes | Status of added progression (start, complete, fail). |
progression01 | string | yes | 1st progression (e.g. world01). |
progression02 | string | no | 2nd progression (e.g. level01). |
progression03 | string | no | 3rd progression (e.g. phase01). |
score | int | no | The player’s score. |
If you do not need progression02
or progression03
do not make any references to these parameters when calling the method. Below you can learn from an example of progression event that uses only progression01
and progression02
:
GameAnalytics.NewProgressionEvent (GAProgressionStatus.Start, "World1");
GameAnalytics.NewProgressionEvent (GAProgressionStatus.Complete, "World1", score);
GameAnalytics.NewProgressionEvent (GAProgressionStatus.Start, "World1", "Level1");
GameAnalytics.NewProgressionEvent (GAProgressionStatus.Complete, "World1", "Level1", score);
GameAnalytics.NewProgressionEvent (GAProgressionStatus.Start, "World1", "Level1", "Phase1");
GameAnalytics.NewProgressionEvent (GAProgressionStatus.Complete, "World1", "Level1", "Phase1", score);
Error Events
To add a custom error event you can call the following function:
GameAnalytics.NewErrorEvent (GAErrorSeverity severity, string message)
The arguments for this event are described below:
Field | Type | Required | Description | Example |
---|---|---|---|---|
severity | enum | yes | Severity of error (critical, debug, error, info, warning). | GAErrorSeverity.Warning |
message | string | yes | Error | message (Optional, can be null). |
Custom Error Event Fields
It is possible to use a set of key-value pairs to add extra fields but it will only be available through raw data export. Here is an example of how to use it:
Dictionary<string, object> fields = new Dictionary<string, object>();
fields.put("test", 100);
fields.put("test_2", "hello_world");
GameAnalytics.NewErrorEvent (severity, message, fields);
For more information on custom event fields and raw data export go here.
Design Events
To add a design event call the following function:
GameAnalytics.NewDesignEvent (string eventName, float eventValue)
Field | Type | Required | Description |
---|---|---|---|
eventName | string | yes | The event string can have 1 to 5 parts. The parts are separated by ‘:’ with a max length of 64 each. e.g. “world1:kill:robot:laser”. The parts can be written only with a-zA-Z, 0-9, -_.,:()!? characters. |
eventValue | float | no | Number value of event. |
Custom Design Event Fields
It is possible to use a set of key-value pairs to add extra fields but it will only be available through raw data export. Here is an example of how to use it:
Dictionary<string, object> fields = new Dictionary<string, object>();
fields.put("test", 100);
fields.put("test_2", "hello_world");
GameAnalytics.NewDesignEvent (eventName, eventValue, fields);
For more information on custom event fields and raw data export go here.