Unity(23.06)

Follow

This document will guide you through the process of Countly SDK installation and it applies to version 23.06.x
You can download the latest release from Github

Click here, to access the documentation for older SDK versions.

The following are some of the key assumptions being considered while developing the SDK. Please take into account the following before integrating this SDK:

  1. Scripting version is based on .NET 4.x equivalent
  2. API Compatibility Level is based on .NET 4.x equivalent
  3. SDK is tested on IOS, Android, Windows, UWP, Linux and Mac OSX

To look at our sample application, download the sample project from Github repo and open the 'EntryPoint.unity' scene. 'EntryPoint.unity' located in 'Example' folder under Assest. There is also 'CountlyEntryPoint.cs' script in Example folder, and this script shows how most of the functionality can be used.

Adding the SDK to the project

Download the Unity package from GitHub and import it into your project.

To import the package (right click on Assets => Import Package => Custom Package => Path_To_Package) and leave all the files checked because we need to import all the files in the package.

Screenshot_2021-03-09_at_6.02.04_PM.png

This SDK uses the Newtonsoft Json package internally and it is required for the SDK to work.

Since Unity version 2020 this package is added to your project automatically by Unity. For versions before that, (2018 and 2019) you have to install this package in the project manually.

One way to do Install the Newtonsoft Json package would be to use the built-in package manager. You would go to Windows => Package Manager. In there you would see something like this:image-newtonsoft.png

SDK Integration

Minimal Setup

Before you can use any functionality, you have to initiate the SDK. 

The shortest way to initiate the SDK is with this code snippet:

CountlyConfiguration config = new CountlyConfiguration
{
AppKey = COUNTLY_APP_KEY,
ServerUrl = COUNTLY_SERVER_URL,
};

Countly.Instance.Init(config);

In the CountlyConfiguration object, you provide appKey and your Countly server URL. Please check here for more information on how to acquire your application key (APP_KEY) and server URL.

If you are in doubt about the correctness of your Countly SDK integration you can learn about the verification methods from here.

SDK logging / debug mode

The first thing you should do while integrating our SDK is enabling logging. If logging is enabled, then our SDK will print out debug messages about its internal state and encountered problems. 

Set EnableConsoleLogging on the config object to enable logging:

CountlyConfiguration config = new CountlyConfiguration
{
AppKey = COUNTLY_APP_KEY,
ServerUrl = COUNTLY_SERVER_URL,
EnableConsoleLogging = true
};

For more information on where to find the SDK logs you can check the documentation here.

Device ID

All tracked information is tied to a "device ID". A device ID is a unique identifier for your users.

You may specify the device ID by yourself if you have one (it has to be unique for each of your users). It may be an email or some other internal ID used by your other systems.

CountlyConfiguration config = new CountlyConfiguration
{
AppKey = COUNTLY_APP_KEY,
ServerUrl = COUNTLY_SERVER_URL,
EnableConsoleLogging = true,
DeviceId = UNIQUE_DEVICE_ID
};

Countly.Instance.Init(config);

You may let Countly SDK handle the initial device ID on its own. If needed in the future you can change this ID with an appropriate call. Then you would use the following config:

CountlyConfiguration config = new CountlyConfiguration
{
AppKey = COUNTLY_APP_KEY,
ServerUrl = COUNTLY_SERVER_URL,
EnableConsoleLogging = true
};

Countly.Instance.Init(config);

SDK data storage

Countly SDK store data that are meant for your app's use only, within an internal storage volume. If your game saves in external storage, SDK will store data within external storage. You may need to add permission to store data on an SD card. Please read the Required app permissions section for more information.

SDK uses Preferences to keep track of application and user preferences and store private, primitive data in key-value pairs. Operational data is stored in iBoxDB database file, named 'db3.box'. 

The specific path where the database file would be stored is different for different platforms. To determine the specific path where the database is stored, you would look at the value returned by Application.persistentDataPath.

Following are the locations of the database file were used in our sample app:

  • Android: '/storage/emulated/0/Android/data/ly.count.demo/files/db3.box'
  • Linux: 'home/<username>/.config/unity3d/Countly/CountlyDotNetSDK/db3.box'
  • Windows: 'C:/Users/<username>/AppData/LocalLow/Countly/CountlyDotNetSDK/db3.box'
  • Mac OSX: '~/Library/Application Support/Countly/CountlyDotNetSDK/db3.box'
  • iOS: '/var/mobile/Containers/Data/Application/<random-folder-name>/Documents/db3.box'

Required app permissions

If you expect the game to be saved on an SD card or any other type of external storage, set Write Permission to 'External (SDCard). This can be found in your Android platform settings under 'Other Settings'.

When configuring your app, make sure that it has permission to access the internet.

SDK notes

To access the Countly Global Instance use the following code snippet:

Countly.Instance.

Crash reporting

The Countly SDK for Unity can collect Crash Reports, which you may examine and resolve later on the server.

In the SDK all crash-related functionalities can be browsed from the returned interface on:

countly.CrashReports.

Automatic crash handling

The Unity SDK can automatically report uncaught exceptions/crashes in the application to the Countly server. To report uncaught exceptions/crashes automatically, enable enableAutomaticCrashReporting in the SDK configuration.

Handled exceptions

You might catch an exception or similar error during your app’s runtime. You may also log these handled exceptions to monitor how and when they are happening. To log exception use the following code snippet:

await countly.CrashReports.SendCrashReportAsync(ex.Message, ex.StackTrace, null, false); 

Here is the detail of the parameters:

  • message - (Mandatory, string) a string that contains a detailed description of the exception.
  • stackTrace - (Mandatory, string) A string that describes the contents of the call stack.
  • segments - (Optional, ) Custom key/values to be reported.
  • nonfatal -  (Optional, bool) Set false if the error is fatal.

Example:

try
{
throw new DivideByZeroException();
}
catch (Exception ex)
{
await countly.CrashReports.SendCrashReportAsync(ex.Message, ex.StackTrace);


You can also send a segmentation with an exception.


Dictionary<string, object> segmentation = new Dictionary<string, object>{
{ "Action", "click"}
};

try

{
throw new DivideByZeroException();
}
catch (Exception ex)
{
await countly.CrashReports.SendCrashReportAsync(ex.Message, ex.StackTrace, segmentation, true);

If you have handled an exception and it turns out to be fatal to your app, you may use the following calls:

await countly.CrashReports.SendCrashReportAsync(ex.Message, ex.StackTrace, null, false); 
Dictionary<string, object> segmentation = new Dictionary<string, object>{
{ "Action", "click"}
};

await countly.CrashReports.SendCrashReportAsync(ex.Message, ex.StackTrace, segmentation, false);

Crash breadcrumbs

Throughout your app, you can leave crash breadcrumbs. They are short logs that would describe the previous steps that were taken in your app before the crash. After a crash happens, they will be sent together with the crash report.

The following command adds a crash breadcrumb:

countly.CrashReports.AddBreadcrumbs("breadcrumb");

Consent

This feature uses Crashes consent. No additional crash logs will be recorded if consent is required and not given.

Events

An event is any type of action that you can send to a Countly instance, e.g. purchases, changed settings, view enabled, and so on, letting you get valuable information about your application.

The Unity SDK helps record as many events as you want (you can set a threshold limit during initialization), and the system will send them automatically to the server once the threshold limit is reached. By default, Countly tracks only up to 100 events. However, this is also configurable.

In the SDK, all event-related functionalities can be browsed from the returned interface on:

countly.Events.

There are a couple of values that can be set when recording an event. The main one is the key property which would be the identifier/name for that event.  For example, in case a user purchased an item in a game, you could create an event with the key 'purchase'.

Optionally there are also other properties that you might want to set:

  • count -  a whole numerical value that marks how many times this event has happened. The default value for that is 1.
  • sum - This value would be summed across all events in the dashboard. For example, in-app purchase events sum of purchased items. Its default value is 0.
  • duration - Used to record and track the duration of events. The default value is 0.
  • segments - A value where you can provide custom segmentation for your events to track additional information. It is a key and value map. The accepted data types for the value are "String", "Integer", "Double", and "Boolean". All other types will be ignored.

Recording events

Here is a quick way to record an event:

public async Task ReportCustomEventAsync(string key, IDictionary<string, object> segmentation = null, int? count = 1, double? sum = null, double? duration = null)

Based on the example below of an event recording a purchase, here is a quick summary of the information for each usage:

  • Usage 1: how many times the purchase event occurred.
  • Usage 2: how many times the purchase event occurred + the total amount of those purchases.
  • Usage 3: how many times the purchase event occurred + from which countries and application versions those purchases were made.
  • Usage 4: how many times the purchase event occurred + the total amount, both of which are also available, segmented into countries and application versions.
  • Usage 5: how many times the purchase event occurred + the total amount, both of which are also available, segmented by countries and application versions + the total duration of those events.

1. Event key and count

await countly.Events.ReportCustomEventAsync("purchase", count: 1);

2. Event key, count, and sum

await countly.Events.ReportCustomEventAsync(key: "purchase", count: 1, sum: 0.99);

3. Event key and count with segmentation(s)

Dictionary<string, object> segmentation = new Dictionary<string, object>
{
{ "country", "Germany" },
{ "app_version", "1.0" }
}; await countly.Events.ReportCustomEventAsync(key: "purchase", segmentation: segmentation, count: 1);

4. Event key, count, and sum with segmentation(s)

Dictionary<string, object> segmentation = new Dictionary<string, object>
{
{ "country", "Germany" },
{ "app_version", "1.0" }
}; await countly.Events.ReportCustomEventAsync(key: "purchase", segmentation: segmentation, count: 1, sum: 0.99);

5. Event key, count, sum, and duration with segmentation(s)

Dictionary<string, object> segmentation = new Dictionary<string, object>
{
{ "country", "Germany" },
{ "app_version", "1.0" }
}; await countly.Events.ReportCustomEventAsync(key: "purchase", segmentation: segmentation, count: 1, sum: 0.99, duration: 60);

These are only a few examples of what you can do with Events. You may go beyond those examples and use country, app_version, game_level, time_of_day, and any other segmentation of your choice that will provide you with valuable insights.

Timed events

It's possible to create timed events by defining a start and a stop moment.

string eventName = "Some event";

//start some event
Countly.Instance.Events.StartEvent(eventName);
//wait some time

//end the event 
Countly.Instance.Events.EndEvent(eventName);

You may also provide additional information when ending an event. In that case you can provide the segmentation, count, or sum values. The default values for those are "null", 1, and 0.

string eventName = "Some event";

//start some event
Countly.Instance.Events.StartEvent(eventName);
//wait some time

IDictionary<string, object> segmentation = new Dictionary<string, object>();
segmentation.Add("wall", "orange");

//end the event while also providing segmentation information
Countly.Instance.Events.EndEvent(eventName, segmentation);

Here are other options to end timed events:

//end the event while providing segmentation information and count
Countly.Instance.Events.EndEvent("timed-event", segmentation, 4);

//end the event while providing segmentation information, count and sum Countly.Instance.Events.EndEvent("timed-event", segmentation, 4, 10);

You may cancel the started timed event in case it is not relevant anymore:

//start some event
Countly.Instance.Events.StartEvent(eventName);
//wait some time

//cancel the event 
Countly.Instance.Events.CancelEvent(eventName);

Consent

This feature uses Events consent. No additional events will be recorded if consent is required and not given.

When consent is removed, all previously started timed events will be canceled.

Sessions

Automatic session tracking 

The Unity SDK handles the session automatically. After calling the Init method, the SDK starts the session automatically and extending the session after every 60 seconds. This value is configured during initialization. It cannot be modified after initialization.

The SDK ends the current session whenever the user quits the app or app goes into the background. A session would be started again when the app comes to the foreground.

Disable automatic session tracking 

You might want to disable automatic session tracking. To do so, use the following code snippet before init call.

config.DisableAutomaticSessionTracking();

Note that after disabling session tracking, the following things would happen:

  • Session information would not be recorded 
  • Device metrics would not be recorded
  • On dashboard location map would not be updated and, overview and analytics session related to sessions and users would all be empty

Consent

This feature requiresSessions consent. Sessions and metrics will not be recorded if consent is required and not given.

If consent was given and then is removed, the current session will not get explicitly ended.

If consent was removed and then given, and automatic sessions were enabled, a session will automatically be started.

View tracking

Manual view recording

The Countly Unity SDK supports manual view (screen) tracking. With this feature, you can report what views a user did and for how long. Thus, whenever there is a screen switch in your app, you can report it to the Countly server by using the following method:

await Countly.Instance.Views.RecordOpenViewAsync("Home Scene");

While manually tracking views, you may add your custom segmentation to them like this:

Dictionary<string, object> viewSegmentation= new Dictionary<string, object>();
viewSegmentation.Add("Cats", 123);
viewSegmentation.Add("Moons", 9.98);
viewSegmentation.Add("Moose", "Deer");

await Countly.Instance.Views.RecordOpenViewAsync("Better view", viewSegmentation);

Note: The accepted data types for the segmentation value are "String", "Integer", "Double", and "Boolean". All other types will be ignored.

When the screen closes you can report it to the server by using the following method:

await Countly.Instance.Views.RecordCloseViewAsync("Home Scene");

To review the resulting data, open the dashboard and go to Analytics > Views. For more information on how to use view tracking data to its fullest potential, click here.

Consent

This feature requiresViews consent. No additional views will be recorded if consent is required and not given.

Device ID management

A device ID is a unique identifier for your users. You may specify the device ID yourself or allow the SDK to generate it. When providing one yourself, keep in mind that it has to be unique for all users. Some potential sources for such an id may be the users username, email or some other internal ID used by your other systems.

Device ID generation

If no device ID is provided the first time the SDK is initialised, the SDK will generate a unique device ID. The source of that id isSystemInfo.deviceUniqueIdentifierwhich is a value exposed by Unity. It should be unique for every device.

Here are the underlying mechanisms used to generate that value for some platforms:

IOS: on pre-iOS7 devices, it will return a hash of the MAC address. On iOS7 devices, it will be

UIDevice identifierForVendor or, if that fails for any reason,

ASIdentifierManager advertisingIdentifier

 Android: SystemInfo.deviceUniqueIdentifier returns the md5 of ANDROID_ID.
Note that since Android 8.0 (API level 26) ANDROID_ID depends on the app signing key. That means "unsigned" builds (which are by default signed with a debug keystore) will have a different value than signed builds (which are signed with a key provided in the player settings). 

Windows Store Apps: uses AdvertisingManager::AdvertisingIdfor returning unique device identifiers.

Windows Standalone: returns a hash from the concatenation of strings taken from Computer System Hardware Classes.
For more information, click here.

Changing device ID

The SDK allows you to change the Device ID at any point in time. You can use any of the following two methods to changing the Device ID, depending on your needs.

Changing Device ID with server merge

In case your application authenticates users, you might want to change the ID to the one in your backend after he has logged in. This helps you identify a specific user with a specific ID on a device he logs in, and the same scenario can also be used in cases this user logs in using a different way (e.g another tablet, another mobile phone, or web). In this case, any data stored in your Countly server database associated with the current device ID will be transferred (merged) into the user profile with the device id you specified in the following method call:

await countly.Device.ChangeDeviceIdAndMergeSessionDataAsync("New Device Id");

Changing Device ID without server merge

You might want to track information about another separate user that starts using your app (changing apps account), or your app enters a state where you no longer can verify the identity of the current user (user logs out). In that case, you can change the current device ID to a new one without merging their data. You would call:

await countly.Device.ChangeDeviceIDAndEndCurrentSessionAsync("New Device Id");

Doing it this way, will not merge the previously acquired data with the new id.

If device ID is changed without merging and consent was enabled, all previously given consent will be removed. This means that all features will cease to function until new consent has been given again for that new device ID.

Do note that every time you change your deviceId without a merge, it will be interpreted as a new user. Therefore implementing id management in a bad way could inflate the users count by quite a lot.

Retrieving current device ID 

You may want to see what device id Countly is assigning for the specific device. For that, you may use the following calls. 

string usedId = Countly.Instance.Device.DeviceId;

You can get the current device ID type. The id type is an enum with the possible values of:

  • SDKGenerated - device ID generated by the SDK
  • DeveloperProvided - device ID provided by the host app
DeviceIdType type = Countly.Instance.Device.DeviceIdType;

Consent

No consent is required to change device ID.

If device ID is changed without merging and consent was enabled, all previously given consent will be removed. This means that all features will cease to function until new consent has been given again for that new device ID.

Push notifications

The Unity SKD uses FCM and APNs as push notification providers for Android and iOS platforms respectively, and it doesn't support the Huawei Push Kit push service.

By default, FCM and APNs dependencies are added as part of the SDK. They can be removed in case you don't need them.

Note that SDK doesn't support Deep linking, Data only push, and Rich push notifications yet. You can send text push notifications only.

Integration

Android

The Countly server needs an FCM server key to send notifications through FCM.

To set it up, refer to Android documentation and follow the following steps:

  1. Download google-services.json from Firebase console.
  2. Create google-services.xml from google-services.json. You can use an online converter here.
  3. Put your file google-services.xml in /Plugins/Android/Notifications/res/values (replace if necessary).

iOS

The Countly server needs the APNs Auth Key to send notifications. To get the APNs Auth Key and upload it to the County Server, for further information refer to iOS Documentation.

To set up push for iOS, follow the next two steps:

1. In Unity, go to Player Settings. In the Other Settings section, add the "COUNTLY_ENABLE_IOS_PUSH"  symbol in Scripting Define Symbols.Screenshot_2020-10-27_at_4.07.16_PM.png

2. After exporting the iOS project, open the project in Xcode, and add Push Notifications Capability. For further information regarding iOS app configuring refer to iOS Documentation.

Enabling push

By default Push Notifications are disabled. To enable push, set Notification mode other than None in the Configuration before SDK init call.

Example:

CountlyConfiguration config = new CountlyConfiguration
{
AppKey = COUNTLY_APP_KEY,
ServerUrl = COUNTLY_SERVER_URL,
EnableConsoleLogging = true,
NotificationMode = TestMode.AndroidTestToken
};

Here is an overview of notification modes:

  • None- it is the default value of notification mode. This mode disables the notification feature.
  • AndroidTestToken / iOSTestToken- during development build, use AndroidTestToken and iOSTestToken modes for Android and iOS platforms respectively.
  • iOSAdHocToken - use this for distribution of iOS builds on TestFlight and AdHoc.
  • ProductionToken - use this mode for the production builds.

Removing push and its dependencies

By default, push dependencies are part of the SDK. You may remove them, and add them back after removing them.
Don't forget to change notification mode to None, after removing push notification dependencies from SDK.

Android

To remove FCM dependencies from the android build, go to the Assets\Plugins\Android folder and delete the Notifications folder.

To add them back after removing, re-import the Unity package.

IOS

The APN's dependencies are part of the SDK. To remove the APNs dependencies, go to the Assets\Plugins folder and delete the iOS folder. Remove the "COUNTLY_ENABLE_IOS_PUSH" symbol from Scripting Define Symbols in Player Settings.

To add them back after removing, re-import the Unity package and add back the "COUNTLY_ENABLE_IOS_PUSH" symbol.

Customizing push messages

Android

To change the sound and icons of the android notifications, update the sound and icons in the folder Assets/Plugins/Android/Notifications/res. 

Note: The Notification channel name and description can be updated through the strings.xml file located in the Assets\Plugins\Android\Notifications\res\values folder.

Handling push callbacks

In order to listen to notification receive and click events, implement INotificationListener interface and its members' methods OnNotificationClicked and OnNotificationReceived into your class. 

Example:


public class CountlyEntryPoint : MonoBehaviour, INotificationListener
{
public void OnNotificationReceived(string message)
{
}

public void OnNotificationClicked(string message, int index)
{
}
}

 There are two ways to register for this class to listen to notification events.

1. You may call AddListener(this)on CountlyConfiguration object before the SDK Init call.

Example:

private void Awake()
{
CountlyConfiguration config = new CountlyConfiguration
{
AppKey = COUNTLY_APP_KEY,
ServerUrl = COUNTLY_SERVER_URL,
};
config.AddListener(this);
Countly.Instance.Init(config);
}

2. If SDK has been initialized, use the following code snippet to listen to push notification events.

Countly.Instance.Notifications.AddListener(this);

To stop listening notification receive and click events, call

Countly.Instance.Notifications.RemoveListener(this);

For more information, check the sample app on Github

Consent

This feature requiresPush consent. No push notifications will be received if consent is required and not given.

User location

While integrating this SDK into your application, you might want to track your user location. You could use this information to better know your app’s user base. There are 4 fields that can be provided:

  • Country code (two-letter ISO standard).
  • City name (must be set together with the country code).
  • Latitude and longitude values separated by a comma, e.g. "56.42345,123.45325".
  • Your user’s IP address.

Setting location

During init, you can set location info in the configuration:

config.SetLocation(countryCode, city, gpsCoordinates, ipAddress);

After SDK initialization, this location info will be sent to the server at the start of the user session.

Note that the IP address will only be updated if set through the init process.

Use Countly.Location. to disable or set the location at any time after the SDK Init call.

For example:

string countryCode = "us";
string city =
"Houston";
string latitude =
"29.634933";
string longitude =
"-95.220255";
string ipAddress =
null; 

Countly.Instance.Location.SetLocation(countryCode, city, latitude + "," + longitude, ipAddress);

When those values are set, a separate request will be created to send them. Except for IP address, because Countly server processes IP address only when starting a session.

If you don't want to set specific fields, set them to null.

Disabling location

Users might want to opt-out of location tracking. To do so, you can disable location during init:

config.DisableLocation();

To disable location after SDK initialization, call:

Countly.Instance.Location.DisableLocation();

These actions will erase the cached location data from the device and the server.

Consent

This feature requiresLocation consent. If consent is not given and is required, no location information will be recorded. No reverse geo IP will be performed server side. SDK will behave as if location tracking is disabled.

If consent was given and then was removed, it will create a request that will clear location information server side.

Remote config

Available in the Enterprise Edition, Remote Config allows you to modify how your app functions or looks by requesting key-value pairs from your Countly server. The returned values may be modified based on the user profile. For more details, please see the Remote Config documentation.

Manual remote config

To download Remote Config, call Countly.Instance.RemoteConfigs.Update(). After the successful download, the SDK stores the updated config locally.

await Countly.Instance.RemoteConfigs.Update();

Accessing remote config values

To access the stored config,  call Countly.Instance.RemoteConfigs.Configs. It will return null if there isn't any config stored.

Dictionary<string, object> config = Countly.Instance.RemoteConfigs.Configs;

The Dictionary<string, object> returns a value of the type object against a key. The developer then needs to cast it to the appropriate type. 

Consent

This feature requiresRemoteConfig consent. If consent is required and not given, no remote config information will be downloaded and stored.

If consent was given and then is removed, locally stored remote config information will be cleared.

User feedback

Ratings

Rating is a customer satisfaction tool that collects direct user feedback. For more details, please see the Rating documentation.

Manual rating reporting

When a user rates your application, you can report it to the Countly server.

Example:

await countly.StarRating.ReportStarRatingAsync(platform: "android", appVersion: "0.1", rating: 3);

All parameters are mandatory.

  • platform - (string) the name of the platform.
  • appVersion - (string) the current version of the app.
  • rating - (int) value from 0 to 5 that will be set as the rating value.

Consent

If consent is required, recording star rating requiresStarRatingconsent. If consent is required and not give, it will not be possible to record star rating.

User profiles

For information about User Profiles, review this documentation.

Setting predefined values

The Countly Unity SDK allows you to upload specific data related to a user to the Countly server. You may set the following predefined data for a particular user:

  • Name: Full name of the user.
  • Username: Username of the user.
  • Email: Email address of the user.
  • Organization: Organization the user is working in.
  • Phone: Phone number.
  • PictureUrl: Web-based Url for the user’s profile.
  • Gender: Gender of the user (use only single char like ‘M’ for Male and ‘F’ for Female).
  • BirthYear: Birth year of the user.

The SDK allows you to upload user details using the methods listed below.

Example:

CountlyUserDetailsModel userDetails = new CountlyUserDetailsModel(name: "Full Name", username: "username", email: "useremail@email.com", organization: "Organization", phone: "222-222-222", pictureUrl: "http://webresizer.com/images2/bird1_after.jpg", gender: "M", birthYear: "1986", null);
await Countly.Instance.UserDetails.SetUserDetailsAsync(userDetails);

Setting custom values

The SDK gives you the flexibility to send only the custom data to Countly servers, even when you don’t want to send other user-related data. You first need to create an instance of the class CountlyUserDetailsModel. All the parameters expected in the constructor remain the same. You can leave all parameters as null and just provide the custom data segment for sending custom data to the Countly server.

Example:

CountlyUserDetailsModel userDetails = new CountlyUserDetailsModel( new Dictionary<string, object> { 
{ "Height", "5.8" },
{ "Mole", "Lower Left Cheek" }
});
await Countly.Instance.UserDetails.SetCustomUserDetailsAsync(userDetails);

Setting User picture

The SDK allows you to set the user's picture URL along with other details using the methods listed below.

Example:

CountlyUserDetailsModel userDetails = new CountlyUserDetailsModel(name: "Full Name", username: "username", email: "useremail@email.com", organization: "Organization", phone: "222-222-222", pictureUrl: "http://webresizer.com/images2/bird1_after.jpg", gender: "M", birthYear: "1986", null);
await Countly.Instance.UserDetails.SetUserDetailsAsync(userDetails);

Modifying data

You may also perform different manipulations to your custom data values, such as incrementing the current value on a server or storing an array of values under the same property.

You will find the list of available manipulations below:

//set one custom properties
await Countly.Instance.UserDetails.Set("test", "test");
//increment used value by 1 await Countly.Instance.UserDetails.Increment("used");
//increment used value by provided value await Countly.Instance.UserDetails.IncrementBy("used", 2);
//multiply value by provided value await Countly.Instance.UserDetails.Multiply("used", 3);
//save maximal value await Countly.Instance.UserDetails.Max("highscore", 300);
//save minimal value await Countly.Instance.UserDetails.Min("best_time",60);
//set value if it does not exist await Countly.Instance.UserDetails.SetOnce("tag", "test");
//insert value to array of unique values await Countly.Instance.UserDetails.PushUnique("type", new string[] {"morning"});
//insert value to array which can have duplicates await Countly.Instance.UserDetails.Push("type", new string[] {"morning"});
//remove value from array await Countly.Instance.UserDetails.Pull("type", new string[] {"morning"}); //send provided values to server await Countly.Instance.UserDetails.SaveAsync()

In the end, always call await Countly.Instance.UserDetails.SaveAsync(); to send them to the server.

Apart from updating a single property in one request, you can modify multiple (unique) properties in one single request. This way you can increment Weight and multiply Height in the same request. Similarly, you can record any number of modified requests and Save them all together in one single request instead of multiple requests.

Note that if you are going to modify multiple properties in one request, make sure your properties are unique, i.e. a property shouldn’t be modified more than once in a single request. However, if you record a property more than once, only the latest value will be posted to the server. 

Example:

Countly.Instance.UserDetails.Max("Weight", 90);
Countly.Instance.UserDetails.SetOnce("Distance", "10KM");
Countly.Instance.UserDetails.Push("Mole", new string[] { "Left Cheek", "Back", "Toe" }); ;
await Countly.Instance.UserDetails.SaveAsync();

Consent

This feature requiresUserconsent. If consent is required and not given, it will not be possible to record user profile information.

User consent

In an effort to comply with GDPR, starting from 20.11.1, Unity Countly SDK provides ways to toggle different Countly features on/off depending on the given consent.

More information about GDPR can be found here.

Setup during init

The requirement for consent is disabled by default. To enable it, you will have to set RequiresConsent value true before initializing Countly.

CountlyConfiguration configuration = new CountlyConfiguration {
ServerUrl = "https://try.count.ly/",
AppKey = "YOUR_APP_KEY",
EnableConsoleLogging = true,
NotificationMode = TestMode.AndroidTestToken,
RequiresConsent = true
};

Countly.Instance.Init(configuration);

By default, when consent is required, no consent is given. If no consent is given, SDK will not work and no network requests related to its features will be sent. When the consent status of a feature is changed, that change will be sent to the Countly server.

Set consent is not persistent and will have to be set each time before Countly init. Therefore, the storage and persistence of the given consent fall on the SDK integrator.

Consent for features may be given and revoked at any time, but if it is given after Countly init, some features may only work in part.

Feature names in the Unity SDK, are stored as Enum called Consents.

The current features are:

* Sessions - tracking when, how often, and how long users use your app

* Events - allow sending events to the server

* Views - allow the tracking of which views user visits

* Location - allow the sending of location information

* Crashes - allow the tracking of crashes, exceptions, and errors

* Users - allow the collecting/providing of user information, including custom properties

* Push - allow push notifications

* StarRating - allow their rating and feedback to be sent

* RemoteConfig - allow downloading remote config values from your server

In case consent is required, you may give consent to features before the SDK Init call. These features consents are not persistent and must be given on every restart.

// prepare consents that should be given
Consents[] consents = new Consents[] { Consents.Users, Consents.Location;
// give consents to the features
configuration.GiveConsent(consents);

After init call, use Countly.Instance.Consents. to change consent.

There are 2 ways of changing feature consent:

  •  GiveConsent/RemoveConsent - gives or removes consent to a specific feature.
// give consent to "sessions" feature
Countly.Instance.Consents.GiveConsent(new Consents[] { Consents.Sessions});
// remove consent from "sessions" feature
Countly.Instance.Consents.RemoveConsent(new Consents[] { Consents.Sessions});
  • GiveConsentAll / RemoveAllConsent- gives or removes all consents.
// Give consent to all features
Countly.Instance.Consent.GiveConsentAll();
// Remove consent from all features
Countly.Instance.Consent.RemoveAllConsent();

Feature groups

Consents may be put into groups. By doing this, you may give/remove consent to multiple features in the same call. Groups may be created using CreateConsentGroup call during SDK configuration. Those groups are not persistent and must be created on every restart. During SDK configuration consents to groups may be given by using GiveConsentToGroup.

// prepare consents that should be added to the group
Consents[] consents = new Consents[] { Consents.Users, Consents.Location;
// create the Consent group
configuration.CreateConsentGroup("User-Consents", consents);
// give consent to the provide consent group
configuration.GiveConsentToGroup("User-Consents");

After init has been called, use GiveConsentToGroup / RemoveConsentOfGroup to give or remove consent for a feature group.

Example:

// prepare array of groups
string[] groupName = new string[]{ "User-Consents", "Events-Consents" };
// give consent to groups
Countly.Instance.Consent.GiveConsentToGroup(groupName);
// remove consent of groups
Countly.Instance.Consent.RemoveConsentOfGroup(groupName);

 

Security and privacy

Parameter tamper protection

You may set the optional salt to be used for calculating the checksum of requested data which will be sent with each request, using the &checksum field. You will need to set exactly the same salt on the Countly server. If the salt on the Countly server is set, all requests would be checked for the validity of the &checksum field before being processed.

configuration.Salt = "salt";

Other Features

SDK Config Parameters Explained

To change the Configuration, update the values of parameters in the "CountlyConfiguration" object. Here are the details of the optional parameters:

DeviceId - (Optional, string) Your Device ID. It is an optional parameter. Example: f16e5af2-8a2a-4f37-965d-qwer5678ui98.

Below you can find details of each parameter:

Salt - (Optional, string) Used to prevent parameter tampering. The default value is NULL

EnablePost - (bool) When set to true, all requests made to the Countly server will be done using HTTP POST. Otherwise, the SDK sends all requests using the HTTP GET method. In some cases, if the data to be sent exceeds the 1800-character limit, the SDK uses the POST method. The default value is false

EnableTestMode - (Optional, bool) This parameter is useful in development when you don't want to send requests to the Countly server. The default value is false.

RequiresConsent - (Optional, bool) This is useful during the app run when the user wants to opt-out of SDK features.

EnableConsoleLogging - (Optional, bool) This parameter is useful when you are debugging your application. When set to true, it basically turns on Logging. 

SessionDuration - (Optional, int) Sets the interval (in seconds) after which the application will automatically extend the session, providing the manual session is disabled. This interval is also used to process requests in the queue. The default value is 60 (seconds).

EventThreshold - (Optional, int) Sets a threshold value that limits the number of events that can be recorded internally by the system before they can all be sent together in one request. Once the threshold limit is reached, the system groups all recorded events and sends them to the server. The default value is 100. 

StoredRequestLimit - (Optional, int) Sets a threshold value that limits the number of requests that can be stored internally by the system. The system processes these requests after every session duration interval has passed. The default value is 1000.

NotificationMode - (Optional, enum) When None, the SDK disables Push Notifications for the device. Use an iOS Test Token or an Android Test Token for testing purposes, and in production use a Production Token. The SDK uses the supplied mode for sending Push Notifications. The default value is None.

EnableAutomaticCrashReporting - (Optional, bool) Used to turn on/off Automatic Crash Reporting. When set to true, the SDK will catch exceptions and automatically report them to the Countly server. The default value is true.

SDK Internal Limits

SDK does have configurable fields to manipulate the internal SDK value and key limits. If values or keys provided by the user, would exceed the limits, they would be truncated. Here are the details of these configurable fields:

MaxKeyLength - (int) Maximum size of all string keys. The default value is 128

MaxValueSize - (int) Maximum size of all values in our key-value pairs. The default value is 256

MaxSegmentationValues - (int) Max amount of custom (dev provided) segmentation in one event. The default value is 30

MaxStackTraceLinesPerThread - (int) Limits how many stack trace lines would be recorded per thread. The default value is 30

MaxStackTraceLineLength - (int) Limits how many characters are allowed per stack trace line. The default value is 200.

Setting Event Queue Threshold

In SDK configuration, you may limit the number of events that can be recorded internally by the system before they can all be sent together in one request. 
Example:

CountlyConfiguration configuration = new CountlyConfiguration {
ServerUrl = "https://try.count.ly/",
AppKey = "YOUR_APP_KEY",
EnableConsoleLogging = true,
NotificationMode = TestMode.AndroidTestToken,
EventThreshold = 1000
};

Countly.Instance.Init(configuration);

Once the threshold limit is reached, the system groups all recorded events and sends them to the server.

Setting Maximum Request Queue Size

When you initialize Countly, you can specify a value for the StoredRequestLimit flag. This flag limits the number of requests that can be stored in the request queue when the Countly server is unavailable or experiencing connection problems.

If the server is down, requests sent to it will be queued on the device. If the number of queued requests becomes excessive, it can cause problems with delivering the requests to the server, and can also take up valuable storage space on the device. To prevent this from happening, the StoredRequestLimit flag limits the number of requests that can be stored in the queue.

If the number of requests in the queue reaches the StoredRequestLimit limit, the oldest requests in the queue will be dropped, and the newest requests will take their place. This ensures that the queue doesn't become too large, and that the most recent requests are prioritized for delivery.

If you do not specify a value for the StoredRequestLimit flag, the default setting of 1,000 will be used.

StoredRequestLimit = 5000;

Checking if the SDK has been initialized

In case you would like to check if init has been called, you may use the following property:

Countly.Instance.IsSDKInitialized;

FAQ

What information is collected by the SDK

The following description mentions data that is collected by SDK to perform their functions and implement the required features. Before any of it is sent to the server, it is stored locally.

* When sending any network requests to the server, the following things are sent in addition to the main data:
- Timestamp of when the request is created
- Current hour
- Current day of week
- Current timezone
- SDK version
- SDK name

* If sessions are used then it would record the session start time, end time, and duration

* If sessions are used then also device metrics are collected which contains:
- Device model
- Screen resolution
- Screen density
- OS name
- OS version
- App version
- Locale identifier

* When generating a device ID, if no custom ID is provided, the SDK will use:
- Android: md5 of ANDROID_ID 
- iOS: It will be vendor id and advertising id as a fallback
- Windows stores apps: It will be advertising id
- Windows Standalone: It will be hash from the concatenation of strings taken from computer system hardware classes.

* If push notification is used:
- The devices push notification token
- If the user clicks on the notification then the time of the click and on which button the user has clicked on 

* When events are recorded, the following information collected:
- Time of event
- Current hour
- Current day of week

* If crash tracking is enabled, it will collect the following information at the time of the crash:
- OS name
- OS version
- Device model
- Device architecture
- The graphics API type
- Device resolution
- App version
- Time of the crash
- Crash stack trace
- Error description
- Total RAM
- Device battery level
- Device orientation
- The type of Internet reachability
- If there is a network connection
- If the app is in the background
- How long has the application been running

Any other information like data in events, location, user profile information, or other manual requests depends on what the developer decides to provide and is not collected by the SDK itself.

Looking for help?