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
Business Events
Used for tracking real-money in-app purchases (IAP).
Some configuration is needed before receipt validation will be active. Read information about validation and requirements for different platforms here.
There are two ways to send a validated business event:
- IAP Validation (SDK 7.2.0 and later): pass the store, product ID and purchase token in a
ReceiptInfoobject. - Legacy: pass the raw receipt and its signature.
- IAP Validation
- Legacy
| 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 |
| receiptInfo | ReceiptInfo | Receipt of the store purchase. Cannot be null | ReceiptInfo.googlePlay(productId, purchaseToken) |
Create the ReceiptInfo with ReceiptInfo.googlePlay(productId, purchaseToken):
| Field | Type | Description |
|---|---|---|
| productId | string | The product ID of the purchased item. Cannot be empty |
| purchaseToken | string | The purchase token returned by Google Play for this purchase. Cannot be empty |
Add a business event when an in-app purchase is completed:
import com.gameanalytics.sdk.events.ReceiptInfo;
ReceiptInfo receiptInfo = ReceiptInfo.googlePlay("[productId]", "[purchaseToken]");
GameAnalytics.addBusinessEvent("USD", 1000, "item", "id", "cart", receiptInfo);
The SDK validates receiptInfo before sending the event. If it is null, or the product ID or purchase token is empty, the event is not sent. To track a purchase without a receipt, use GameAnalytics.addBusinessEvent("USD", 1000, "item", "id", "cart");.
| 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 |
| receipt | string | INAPP_PURCHASE_DATA. Null allowed. Read more about Android receipt here | |
| store | string | App store used. Always google_play | google_play |
| signature | base64 string | INAPP_DATA_SIGNATURE. Null allowed. Read more about Android signature here |
Add a business event when an in-app purchase is completed:
GameAnalytics.addBusinessEvent("USD", 1000, "item", "id", "cart", "[receipt]", "google_play", "[signature]");
If the receipt/signature is null (or is an invalid receipt) then it will be submitted to the GA server but will register as not validated.
Custom Event Fields
- IAP Validation
- Legacy
HashMap<String, Object> fields = new HashMap<>();
fields.put("test", 100);
fields.put("test_2", "hello_world");
ReceiptInfo receiptInfo = ReceiptInfo.googlePlay("[productId]", "[purchaseToken]");
GameAnalytics.addBusinessEvent("USD", 1000, "item", "id", "cart", receiptInfo, fields);
HashMap<String, Object> fields = new HashMap<>();
fields.put("test", 100);
fields.put("test_2", "hello_world");
GameAnalytics.addBusinessEvent("USD", 1000, "item", "id", "cart", "[receipt]", "google_play", "[signature]", fields);
Find more information on Custom Event Fields and Data Export following the links.
For more information on Business Events go here.
Ad Events
The GameAnalytics ad event should be called when certain ad SDK events occur (show, click, reward, fail).
The ad SDK name argument must be all lower-case with no spaces or underscores. Examples of valid values:
- admob
- unityads
- ironsource
- applovin
Rewarded Video
Showing a Rewarded Video
Track if an ad fails to show:
if (rewardedVideoAd != null && rewardedVideoAd.isLoaded()) {
rewardedVideoAd.show();
}
else
{
GameAnalytics.addAdEvent(GAAdAction.FailedShow, GAAdType.RewardedVideo, "admob", "[AD_PLACEMENT_OR_UNIT_ID]");
}
Track Time Spent
Track how long the user watched by starting a timer when the ad opens:
@Override
public void onRewardedVideoAdOpened() {
currentRewardedVideoPlacement = "[AD_PLACEMENT_OR_UNIT_ID]";
GameAnalytics.startTimer(currentRewardedVideoPlacement);
}
@Override
public void onPause() {
if(currentRewardedVideoPlacement != null)
{
GameAnalytics.pauseTimer(currentRewardedVideoPlacement);
}
}
@Override
public void onResume() {
if(currentRewardedVideoPlacement != null)
{
GameAnalytics.resumeTimer(currentRewardedVideoPlacement);
}
}
Tracking Ad Rewards
@Override
public void onRewarded(RewardItem reward) {
GameAnalytics.addAdEvent(GAAdAction.RewardReceived, GAAdType.RewardedVideo, "admob", "[AD_PLACEMENT_OR_UNIT_ID]");
}
Tracking Successful Ads
@Override
public void onRewardedVideoAdClosed() {
if(currentRewardedVideoPlacement != null)
{
long elapsedTime = GameAnalytics.stopTimer(currentRewardedVideoPlacement);
GameAnalytics.addAdEvent(GAAdAction.Show, GAAdType.RewardedVideo, "admob", "[AD_PLACEMENT_OR_UNIT_ID]", elapsedTime);
currentRewardedVideoPlacement = null;
}
}
Interstitial
if (interstitialAd != null && interstitialAd.isLoaded()) {
interstitialAd.show();
GameAnalytics.addAdEvent(GAAdAction.Show, GAAdType.Interstitial,"admob", "[AD_PLACEMENT_OR_UNIT_ID]");
}
else
{
GameAnalytics.addAdEvent(GAAdAction.FailedShow, GAAdType.Interstitial, "admob", "[AD_PLACEMENT_OR_UNIT_ID]");
}
Banner
if (bannerAd != null && bannerAd.isLoaded()) {
bannerAd.show();
GameAnalytics.addAdEvent(GAAdAction.Show, GAAdType.Banner,"admob", "[AD_PLACEMENT_OR_UNIT_ID]");
}
else
{
GameAnalytics.addAdEvent(GAAdAction.FailedShow, GAAdType.Banner, "admob", "[AD_PLACEMENT_OR_UNIT_ID]");
}
Ad Event Fields
| Field | Type | Description | Example |
|---|---|---|---|
| adAction | enum | A defined enum for ad action | GAAdAction.Clicked GAAdAction.Show GAAdAction.FailedShow GAAdAction.RewardReceived |
| adType | enum | A defined enum for ad type | 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 placement in the game | level_complete_ad |
| duration | int | Optional. Only used for video ads to track watch time | 10 |
| noAdReason | enum | Optional. Reason for not being able to show an ad | GAAdError.Unknown GAAdError.Offline GAAdError.NoFill GAAdError.InternalError |
For more information on Ad Events go here.
Impression Events
Impression events capture ad impression data from ad networks. Supported networks:
- Fyber
- IronSource
- TopOn
- MAX
- Aequus
- AdMob
IronSource
protected void onCreate(Bundle savedInstanceState)
{
IronSource.setImpressionDataListener(new ImpressionDataListener()
{
@Override
public void onImpressionSuccess(ImpressionData impressionData)
{
GameAnalytics.addImpressionIronSourceEvent(IronSourceUtils.getSDKVersion(), impressionData.getAllData());
}
});
}
MAX
protected void onCreate(Bundle savedInstanceState)
{
maxInterstitial.setAdListener(new MaxAdListener()
{
@Override
public void onAdDisplayed(MaxAd ad)
{
JSONObject json = new JSONObject();
try
{
json.put("country", AppLovinSdk.getInstance(referenceToActivity).getConfiguration().getCountryCode());
json.put("network_name", ad.getNetworkName());
json.put("adunit_id", ad.getAdUnitId());
json.put("adunit_format", ad.getFormat().getLabel());
json.put("placement", ad.getPlacement());
json.put("creative_id", ad.getCreativeId());
json.put("revenue", ad.getRevenue());
}
catch(JSONException e)
{
}
GameAnalytics.addImpressionMaxEvent( AppLovinSdk.VERSION, json);
}
});
}
Custom Impression Event Fields
HashMap<String, Object> fields = new HashMap<>();
fields.put("test", 100);
fields.put("test_2", "hello_world");
GameAnalytics.addImpressionEvent([adNetworkName], [adNetworkVersion], [impressionData], fields);
Find more information on Custom Event Fields and Data Export following the links.
For more information on Impression Events go here.
Resource Events
Used to track the flow of virtual currencies — the sink (subtract) and source (add) for each currency.
Before calling the resource event, specify what currencies and item types can be used in the Configuration phase.
| Field | Type | Required | Description |
|---|---|---|---|
| flowType | enum | yes | Add (source) or subtract (sink) resource |
| currency | string | yes | One of the available currencies set in configuration. 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 |
| itemId | string | yes | Item id (string max length = 32) |
GameAnalytics.addResourceEventWithFlowType(GAResourceFlowType.Source, "Gems", 400, "IAP", "Coins400");
// sink (subtract) Gem currency to buy an item.
GameAnalytics.addResourceEventWithFlowType(GAResourceFlowType.Sink, "Gems", 400, "Weapons", "SwordOfFire");
Custom Resource Event Fields
HashMap<String, Object> fields = new HashMap<>();
fields.put("test", 100);
fields.put("test_2", "hello_world");
GameAnalytics.addResourceEventWithFlowType(GAResourceFlowType.Sink, "BeamBooster", 3, "Gameplay", "BeamBooster5Pack", fields);
Be careful to not call the resource event too often! Count collected resources and send a single Source event when the level completes or fails.
For more information on Resource Events go here.
Progression Events
Used to track player progression through a 3-tier hierarchy (e.g. world:stage:level).
| Field | Type | Required | Description |
|---|---|---|---|
| progressionStatus | enum | yes | Start, Complete or 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 |
Add a progression start event:
GameAnalytics.addProgressionEventWithProgressionStatus(GAProgressionStatus.Start, "world01", "stage01", "level01");
Not all 3 tiers are required:
progression01onlyprogression01andprogression02progression01,progression02, andprogression03
Custom Progression Event Fields
HashMap<String, Object> fields = new HashMap<>();
fields.put("test", 100);
fields.put("test_2", "hello_world");
GameAnalytics.addResourceEventWithFlowType(GAResourceFlowType.Sink, "BeamBooster", 3, "Gameplay", "BeamBooster5Pack", fields);
For more information on Progression Events go here.
Error Events
Used to send manual error reports to GameAnalytics.
| Field | Type | Required | Description |
|---|---|---|---|
| severity | enum | yes | GAErrorSeverity.GAErrorSeverityDebug GAErrorSeverity.GAErrorSeverityInfo GAErrorSeverity.GAErrorSeverityWarning GAErrorSeverity.GAErrorSeverityError GAErrorSeverity.GAErrorSeverityCritical |
| message | string | no | Custom error message |
GameAnalytics.addErrorEventWithSeverity(GAErrorSeverity.GAErrorSeverityDebug, "Something went bad in some of the smelly code!");
Custom Error Event Fields
HashMap<String, Object> fields = new HashMap<>();
fields.put("test", 100);
fields.put("test_2", "hello_world");
GameAnalytics.addErrorEventWithSeverity(GAErrorSeverity.GAErrorSeverityDebug, "Something went bad in some of the smelly code!", fields);
Design Events
Custom events that allow for a 5-part event ID hierarchy separated by colons.
| Field | Type | Required | Description |
|---|---|---|---|
| eventId | string | yes | Event ID (up to 5 parts separated by :, max 64 chars each) |
| value | float | no | Optional numeric value |
GameAnalytics.addDesignEventWithEventId("Kill:Sword:Robot");
Optionally attach a float value:
GameAnalytics.addDesignEventWithEventId("BossFights:FireLord:KillTimeUsed", 234);
Custom Design Event Fields
HashMap<String, Object> fields = new HashMap<>();
fields.put("test", 100);
fields.put("test_2", "hello_world");
GameAnalytics.addDesignEventWithEventId("BossFights:FireLord:KillTimeUsed", 234, fields);
Do not generate an excessive number of unique event hierarchy nodes. A maximum of around 10k unique nodes should be the limit. Use the value field for numeric data rather than embedding it in the event string.
For more information on Design Events go here.