Skip to content

Analytics

Analytics in IdleKit are handled via a service provided by IdleKit called Kraang. Using the provided Analytics package you can get setup and sending events quickly.

Setup

Everything you need to get Analytics up and running is provided. Just follow the steps below and reach out to your support contact if anything is confusing or not working correctly.

  • Contact IdleKit if needed to get access to the Analytics Onboarding documentation.
  • Make sure that you have the App ID and App Secret. You can get these from your support contact if they have not already been provided.
  • Add the idlekit-analytics package to your projects manifest.json file.
"com.idlekit.analytics": "ssh://git[com](github/com)/Idlekit/idlekit-analytics.git#[release-branch]"

Implementation

Enable Kraang

  • Open your Unity project.
  • Open the Project Settings window and navigate to the Player area.
  • Add IDLEKIT_ANALYTICS_KRAANG to the Scripting Define Sysmbols.
  • Click on IdleKit -> Setup -> Analytics -> Kraang Analytics Assets to generate default configuration.
  • Select the Assets/IdleKit/Analytics/Kraang/KraangDispatcherConfig.asset file and view it in the Inspector.
  • Fill in the App Id and App Secret fields with the information you were provided with.

Note

The configuration files appear in a folder at: Assets/IdleKit/Analytics/Kraang/ and are automatically added to the Addressables database.

Create Your Game Specific User Data

Each project must create a class that is used to send game specific information. This class is passed into the Kraang initialization.

  • Create a new class in your project with a name in the style of [ProjectName]AnalyticsUserData.
  • Add the following code to the new class and change anything in [] to an appropriate value.
using System;
using System.Collections.Generic;
using IdleKit.Analytics;
using IdleKit.Gameplay;
using IdleKit.Core;
using UnityEngine;

namespace [Project.Namespace]
{
    [Serializable]
    public class [ProjectName]AnalyticsUserData : KraangUserDataBase
    {
        private IResolver _resolver;
        private IUserSavedData _userSavedData;
        private IEntityLoaderService _entityLoaderService;

        public override void Inject(IResolver resolver)
        {
            _resolver = resolver;
            _userSavedData = resolver.Resolve<IUserSavedData>();
            _entityLoaderSesrvice = resolver.Resolve<IEntityLoaderService>();
        }

        // Overriding this method allows you to inject user and game specific data into Analytics events.
        public override Dictionary<string, object> GetUserData()
        {
            // Some events happen before IdleKit has been initialized.
            int level = 1;
            if (_resolver.CanResolve<IContentData>())
            {
                IContent content = _entityLoaderService.LoadEntity<IContent, IContentData>(_userSavedData.ContentId);
                level = Array.IndexOf(content.ContentData.StageIds, content.ContentSavedData.CurrentStageId) + 1;
            }

            _id = SystemInfo.deviceUniqueIdentifier; // Required. 
            _level = level; // Required.
            _levelVersion = "1"; // Optionally used to track multiple playthroughs.
            _assetVersion = ""; // Optionally used to track the version of the assets the player has downloaded.

            return base.GetUserData();
        }
    }
}
  • Add this class to an Installer. Installers are used to bind classes in our dependency container. You may or may not have a custom Installer so please reach out to your support contact if you need help creating one.
public void Install(IContainer container)
{
    container.Bind<IAnalyticsUserData>().To<[ProjectName]AnalyticsUserData>().AsTransient().Conclude();
}

public void Uninstall(IContainer container)
{
    container.Unbind<IAnalyticsUserData>();
}

Initialize Analytics

  • Add the AnalyticsService and other requirements into the load flow in your IStartup class. Some of the below code might already exist and you can ignore it.
// The EnvironmentProvider lets you define which development environment the code is running in. DEV, STAGE oor PROD.
// These are totally customizable and you can freely adjust them. You can also provide them to the load flow as you see fit.
// This example is just using a simple serialized reference.
[SerializeField]
protected EnvironmentProvider _environmentProvider;

protected override void SetInitializationLoadPhases()
{
    Loader.OnForegroundLoadCompleted += HandlePreloadCompleted;
    Loader.Enqueue(
        SequenceFlow.InSequence,

        // Initialize Addressables. Analytics Configuration is stored in Addressables by default.
        Context.Container.Resolve<InitializeAddressablesPhase>(),

        // Preload required assets.
        Context.Container.Resolve<InitializeServicesPhase>().Initialize(typeof(IAssetService)),
        Context.Container.Resolve<LoadAssetsPhase>().Initialize(CoreConstants.PRELOAD_ASSET_LABEL),

        // Bind and load the EnvironmentConfig. This is used in the Analytics configuration to allow for development and production environments.
        Context.Container.Resolve<BindDataPhase>().Initialize(typeof(IEnvironmentConfig), _environmentProvider),
        Context.Container.Resolve<LoadDataPhase>().Initialize(CoreConstants.CONFIG_ASSET_LABEL),

        // Other Load Phases...

        Context.Container.Resolve<InitializeServicesPhase>().Initialize(

            // Other Services...

            // Analytics Service
            typeof(IAnalyticsService),

            // Analytics Tracking Services. These provide out of the box tracking for common IdleKit events.
            typeof(UserAcquisitionAnalyticsTrackingService),
            typeof(CurrencyChangeAnalyticsTrackingService),
            typeof(ContentProgressionAnalyticsTrackingService)
        ),

        // Other Load Phases...

    );
}

Note

UserAcquisitionAnalyticsTrackingService, CurrencyChangeAnalyticsTrackingService and ContentProgressionAnalyticsTrackingService offer out of the box support for most important events, so it is recommended to include them if they are compatible with your game.

Event Types

  • AnalyticsEventBase - The base class for all Event Types.
  • ABTestEvent - This event should be sent when a user is first assigned a test group for an ongoing A/B Test.
  • AchievementEvent - This event should be sent when a user completes an achievement.
  • AdHocEvent - Useful for tracking simple user interactions, application state and other things not handled by more specific events.
  • ContentSummaryEvent - Used to track summary data for content completion.
  • CurrencyEvent - Track when user's receive or spend currency.
  • DialogSequenceEvent - Track when the user sees dialog screens for story sequences.
  • DownloadPromptEvent - Track when the user has been prompted with a game data download.
  • ErrorEvent - This should be sent any time an exception or other error happens. The AnalyticsService will automatically send these for any uncaught exceptions. See the note below for further information.
  • GachaOpenedEvent - Track when the user has opened gacha and what their reward was.
  • InstallEvent - This should be sent once per user when they load the game for the first time.
  • PlayerDataEvent - This event just wraps an IAnalyticsUserData and appends some device, locale and platform information.
  • PurchaseEvent - Send this event when a user makes a purchase using real currency.
  • PurchaseFailedEvent - Send this event when an attempted purchase using real money fails.
  • PushNotificationEvent - Send when a push notification is sent if possible, or cache some data and send this event when the user opens the app after a notification has been sent.
  • QuestProgressionEvent - Send to track details about when a user begins or finishes a quest or quest-like activity such as goals or milestones.
  • SessionBeginEvent - This event is used to track the start of a users session. The AnalyticsService automatically sends this event.
  • SessionEndEvent - This event is used to track the end of a users session. The AnalyticsService automatically sends this event.

Note

Exceptions can be handled by the Logs class. The exception plus any other relevant information can then be passed to an ErrorEvent. Be careful to only send one event if an exception happens in looping code.

Sending Events

Events can easily be sent via a simple API call to the AnalyticsService.

// Get a reference to the IAnalyticsService
protected IAnalyticsService _analyticsService;

public override void Inject(IResolver resolver)
{
    base.Inject(resolver);

    _analyticsService = resolver.Resolve<IAnalyticsService>();
}

// Send the Event.
_analyticsService.LogEvent<TEvent>(analyticsEvent => {
    // Pass in any relevant values here. The will vary based on the type of Event you are sending.
    analyticsEvent.Initialize();
});

Custom Events

Some custom events can be handled by sending the AdHocEvent with data relevant to the action in question. If your custom event needs more information you will need to follow these steps.

  • Contact IdleKit support and work with them to define the custom event specifications.
  • Create a new Event class and name it appropriately. This class should extend AnalyticsEventBase.
  • Using other Event classes for reference implement the abstract EventName property and override the EventContent() method.
  • Integrate the new Event into the application in the appropriate place.
  • Ensure your new event is serializable so the analytics system can write it to disk should it need to be saved for later.

For example, this is an event that could be fired when a player sends a gift.

using System;
using System.Collections.Generic;
using UnityEngine;

namespace Your.Game
{
    /// <summmary>
    /// Tracks when a player sends a gift and to whom.
    /// </summary>
    [Serializable]
    public class GiftSentEvent : AnalyticsEventBase
    {
        // The EventName property must be overriden to indicate the type of event when sent
        // to the backend.
        public override string EventName = "giftSent";

        // You may optionally override the IncludeDeviceId property to include the device ID
        // within the event payload. This defaults to false.
        protected override bool IncludeDeviceId => true;

        // Any fields need to be serializable so they can be saved to disk.
        [SerializeField]
        protected string _senderId;
        [SerializeField]
        protected string _receiverId;
        [SerializeField]
        protected string[] _itemIds;

        // When you log an event you get to call Initialize with whatever data is necessary.
        public virtual void Initialize(string senderId, string receiverId, string[] itemIds)
        {
            _senderId = senderId;
            _receiverId = receiverId;
            _itemIds = itemIds;
        }

        // Implement the EventContent method to provide a dictionary of values to be placed in
        // the event payload. Most of the time you will simply need to return a dictionary
        // without any other processing.
        protected override Dictionary<string, object> EventContent()
        {
            return new Dictionary<string, object>()
            {
                {"senderId", _senderId},
                {"receiverId", _receiverId},
                {"itemIds", _itemIds},
            };
        }
    }
}

Best Practices

  • Don't send events for actions that happen extremely frequently. A common mistake is to send an analytics event each time currency changes.
  • The default values in the KraangDispatcherConfig for max batch size and send event interval seconds should suffice, but can be changed if needed.
  • Only send events that provide useful information for analysis. Sending events that don't get used in queries later wastes bandwidth for players.