Countly Documentation

Countly Resources

Here you'll find comprehensive guides to help you start working with Countly as quickly as possible.

Windows SDK

This document explains how to install Countly SDK for Windows desktop applications.

Minimum Windows version

Countly Windows SDK supports following operating system versions:

Windows 8.1
Windows 10
Windows 10 Mobile
.NET 3.5
.NET 4.0 Client Profile
.NET 4.5 and above
.NET Standard 2.0
Xamarin (Android, iOS)

SDK in transition

Historically access to the SDK functions we're accessed through "Countly.FunctionName()". Starting from version 18.10.0 it has been refactored to a singleton, which means that it's functions by calling "Countly.Instance.FunctionName()". At the moment it is still backwards compatible for old functionality, but new features can only be accessed through "Countly.Instance". In the future all call will be accessible only through "Countly.Instance". This documentation will not show the usage of depracated calls.

In order to set up Countly SDK in your Windows app, follow these steps:

  1. In Solution Explorer open context menu on References - Manage NuGet Packages.
  2. Select nuget.org in Package source.
  3. Type Countly in search box.
  4. Select Countly Analytics from results list and click Install button.

The usage of the SDK requires a connection to the server. This connection usually is access to the internet.

SDK Set up

Add using CountlySDK; in the usings section

Before you can use any Countly functinality, you need to call Countly.Instance.Init to initiate the SDK.

To that Init call you need to pass a CountlyConfig object where you set up your relevant configuration.

//create the Countly init object
CountlyConfig cc = new CountlyConfig();
cc.serverUrl = "http://YOUR_SERVER";
cc.appKey = "YOUR_APP_KEY";
cc.appVersion = "1.2.3";

//initiate the SDK with your preferences
Countly.Instance.Init(cc);

Note: Make sure you use App Key (found under Management -> Applications) and not API Key. Entering API Key will not work.

Make sure you also fill in YOUR_SERVER part, either with IP address or the name of the server you installed Countly on.

The SDK targets multiple profiles. Therefore for some of them there are feature differences. Either with additional function calls or with additional fields in the CountlyConfig object.

Additional info for Windows Store project setup

As the Countly SDK requires Internet (Client & Server) to be enabled. Open Package.appxmanifest, click on Capabilities section and make it enabled

Add using CountlySDK; in the App.xaml.cs usings section

You need to call Countly.Instance.SessionBegin(); each time when app is activated and await Countly.EndSession(); when app is deactivated.

That would mean adding SessionBegin calls to OnLaunched, OnActivated and OnResuming events and SessionEnd calls to OnLaunched event which is already prepared for you by Visual Studio in App.xaml.cs file. Add initialization code before page navigation happens.

protected override void OnLaunched(LaunchActivatedEventArgs e)
{
  
...

	//create the Countly init object
  CountlyConfig cc = new CountlyConfig();
  cc.serverUrl = "http://YOUR_SERVER";
  cc.appKey = "YOUR_APP_KEY";
  cc.appVersion = "1.2.3";
  cc.application = this

  //initiate the SDK with your preferences
  await Countly.Instance.Init(cc)
  
  if (rootFrame.Content == null)
	{
		// Removes the turnstile navigation for startup.
		if (rootFrame.ContentTransitions != null)
		{
			this.transitions = new TransitionCollection();
			foreach (var c in rootFrame.ContentTransitions)
		{
			this.transitions.Add(c);
		}
	}
    
...
}

Add override method called OnActivated to App.xaml.cs file and call Countly.Instance.SessionBegin(); inside

protected override void OnActivated(IActivatedEventArgs args)
{
	await Countly.Instance.SessionBegin();
}

Subscribe to application Resuming method in App constructor.

public App()
{
	this.InitializeComponent();
	this.Resuming += this.OnResuming;
	this.Suspending += this.OnSuspending;
}

private void OnResuming(object sender, object e)
{
	await Countly.Instance.SessionBegin();
}

Update OnSuspending method created by Visual Studio in App.xaml.cs file to handle Countly deactivation logic. Make sure you use async/await statements, so app will not be closed before Countly receives end session event

private async void OnSuspending(object sender, SuspendingEventArgs e)
{
	var deferral = e.SuspendingOperation.GetDeferral();

	await Countly.Instance.SessionEnd();

	deferral.Complete();
}

Tracking Sessions

After you have initiated the SDK, call Countly.Instance.SessionBegin() when you want to start tracking the user session. Usually that is called in entry point of the app.

Call Countly.Instance.SessionEnd() before app is closed to mark the end of the apps session.

The SDK will send a update request every 60 seconds, to track how long the session is.

That time is tracked using a internal timer. Some usage scenarios (like using the SDK in a console application) can prevent the timer from working. In those circumstances you can manually call Countly.Instance.SessionUpdate(elapsedTime) to track the passage of time. You should still call it about every minute.

//start the user session
Countly.Instance.SessionBegin();
  
//end the user session
Countly.Instance.SessionEnd();

//update the session manually
int elapsedTime = 60;//elapsed time in seconds
Countly.Instance.SessionUpdate(elapsedTime);

Using custom events

In all the examples below we will be recording a purchase event. Here is a quick summary what information each usage will provide us.

Data passed should be in UTF-8

All data passed to Countly instance via SDK or API should be in UTF-8.

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

First, add using CountlySDK; in the usings section

1. Event key and count

Countly.RecordEvent("purchase", 3);

2. Event key, count and sum

Countly.RecordEvent("purchase", 3, 0.99);

3. Event key and count with segmentation(s)

Segmentation segmentation = new Segmentation();
segmentation.Add("country", "Germany");
segmentation.Add("app_version", "1.0");
Countly.RecordEvent("purchase", 3, segmentation);   

Countly.RecordEvent("purchase", 1, 0.99);

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

Segmentation segmentation = new Segmentation();
segmentation.Add("country", "Germany");
segmentation.Add("app_version", "1.0");
Countly.RecordEvent("purchase", 3, 2.97, segmentation);

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

Segmentation segmentation = new Segmentation();
segmentation.Add("country", "Germany");
segmentation.Add("app_version", "1.0");
Countly.RecordEvent("purchase", 3, 2.97, 122.45, segmentation);

Managing DeviceId

To link events, sessions, crashes, etc to a user, a deviceId is used. It is usually generated by the SDK. It is then saved locally and then reused on every init, unless the developer supplies it's own device Id.

Ideally the same device Id would be generated on the same device when using the same generation method. This way it would be possible to track users on reinstalls.

The SDK supports multiple ways for generating that ID, each with it's pro's and con's and some limited to a specific compilation target:

  • cpuId - [net35, net40] uses the OS provided CPU id info to generate a hash that is used as a id. It should be possible to generate the same id on a reinstall if the cpu stays the same. On virtual machines and windows 10 devices is not guaranteed to be unique and generates the same id
  • multipleWindowsFields - [net35, net40] uses multiple OS provided fields (CPU id, disk serial number, windows serial number, windows username, mac address) to generate a hash that would be used as the device Id. This method should regenerate the same id on a reinstall, provided those source fields do not change
  • windowsGUID - [all platforms] generates a random GUID that will be used as a device id. Very high chance of being unique. Will generate a new id on a reinstall.
  • winHardwareToken - [windows 8 store apps] uses the hardware identification token provided by the OS to generate a hash that will be used as a id. Should be the same on a reinstall. Very high chance of being unique
  • developerSupplied - The device Id was provided by the developer. Used in cases where developers want to use a id tied to their internal systems/servers.

Device id and generation method can be provided during SDK init. Those values can also bet not set, then the default method for that target will be used.

//create the Countly init object
CountlyConfig cc = new CountlyConfig();
cc.serverUrl = "http://YOUR_SERVER";
cc.appKey = "YOUR_APP_KEY";
cc.appVersion = "1.2.3";
cc.developerProvidedDeviceId = "use@email.com";

//initiate the SDK with your preferences
Countly.Instance.Init(cc);

It is possible to change the device Id after the app is initiated. It can be done with a server side merge and without one. In both cases the new id will be used on further app launches.

If it is done without a server side merge, then the previous session will end and a new session will be started with the new id.

With a server side merge, the events, session information and etc will be assigned to the new device id.

//changing without a server side merge
Countly.Instance.ChangeDeviceId("newId", false);
Countly.Instance.ChangeDeviceId("newIdAgain");

//changing with a server side merge
Countly.Instance.ChangeDeviceId("ThisIsUnique", true);

Setting up User Profiles

Availability

This feature is available with Enterprise Edition subscription.

You can save info about user tracking data is related to. Countly provides Countly.UserDetails object that exposes user-related properties

Each time you change property value, Countly syncs it with a server. If you set value as null, you will delete the property.

Countly.UserDetails.Name = "John"; // set name to John
Countly.UserDetails.Name = "null"; // remove name

You can provide custom properties for user using Custom object

Countly.UserDetails.Custom.Add("city", "london");

Additionally you can upload picture of the user to the server. Accepted picture formats are .png, .gif and .jpeg and picture will be resized to maximal 150x150 dimensions.

Countly.UserDetails.UploadUserPicture(picture_stream);

Note: dots (.) and dollar signs ($) in key names will be stripped out.

Setting up Crash Reports

Countly SDK has an ability to automatically collect crash reports which you can examine and resolve later on the server. This applies for Windows Store apps, on other platforms you should subscribe to unhandled exceptions handler manually. Exception details and device properties will be sent on next app launch.

To log handled exceptions, which are not fatal, use Countly.RecordException; method. You can provide custom properties for crash providing key/value object to store for this crash report and server will segment values for you for the same crash.

Following command adds crash breadcrumb like log record to the log that will be send together with crash report Countly.AddBreadCrumb;

Seting user location

It's possible to set the user location.

There are 4 fields that can be provided:

  • Comma separate latitude and longitude values, for example "56.42345,123.45325"
  • ip address of your user
  • country code in the 2 letter iso standard
  • city name (has to be set together with country code)
//set user location
String gpsLocation = "63.445821, 10.898868";
String ipAddress = "13.56.33.12";
String country_code = null;
String city = null;

Countly.Instance.SetLocation(gpsLocation, ipAddress, country_code, city);

If there are fields you don't want to set, set them to null. If you want to reset a field, set it to empty string.

If no location is provided, it will be approximated by using geoip.

If you want to disable tracking of location info, you should disable it:

//disable location tracking
Countly.Instance.DisableLocation();

This will also erase all location info server side.

Using SDK sample

The Countly github page for this SDK contains also sample projects. You should be able to download them to test the basic functionality of this SDK and make sure you are using it correct in case you encounter any problems in your application

The project page can be found here

Enabling logging

In order to make sure that requests to Countly are sent correctly, you need to enable logging using following:

    Countly.IsLoggingEnabled = true;

You can turn it on and off in any place of your code. This will print debug messages and give better insight in the inner workings of the SDK.

User Consent management

If you want to comply with GDPR or similar privacy requirements, there is functionality to manage user consent to features.

More information about GDPR can be found here.

By default the requirement for consent is disabled. To enable it, you have to do it with the CountlyConfig object by setting consentRequired to true.

//create the Countly init object
CountlyConfig cc = new CountlyConfig();
cc.serverUrl = "http://YOUR_SERVER";
cc.appKey = "YOUR_APP_KEY";

//enable consent
cc.consentRequired = true;

//initiate the SDK with your preferences
Countly.Instance.Init(cc);

By default no consent is given. That means that if no consent is enabled, Countly will not work and no network requests, related to features, will be sent. When consent status of a feature is changed, that change will be sent to the Countly server.

Cconsent for features is not persistent and will have to be set every time while initializing countly. Therefore the storage and persistance of given consent falls on the sdk integrator.

Feature names in this SDK are stored as a enum called ConsentFeatures.

Features currently supported by this SDK are:

  • sessions - tracking when, how often and how long users use your app
  • events - allow sending custom events to server
  • location - allow sending location information
  • crashes - allow tracking crashes, exceptions and errors
  • users - allow collecting/providing user information, including custom properties

Consent for features can be given or removed at any time. Values are set using Dictionary<ConsentFeatures, bool>. That can be done either during init:

//create the Countly init object
CountlyConfig cc = new CountlyConfig();
cc.serverUrl = "http://YOUR_SERVER";
cc.appKey = "YOUR_APP_KEY";

//enable consent
cc.consentRequired = true;

//set consent features
Dictionary<ConsentFeatures, bool> consent = new Dictionary<ConsentFeatures, bool>();
consent.Add(ConsentFeatures.Crashes, true);
consent.Add(ConsentFeatures.Events, false);
consent.Add(ConsentFeatures.Location, true);
consent.Add(ConsentFeatures.Sessions, false);
consent.Add(ConsentFeatures.Users, false);
cc.givenConsent = consent;

//initiate the SDK with your preferences
Countly.Instance.Init(cc);

It can also be done at any other moment in the app after init:

//preparing consent features
Dictionary<ConsentFeatures, bool> consent = new Dictionary<ConsentFeatures, bool>();
consent.Add(ConsentFeatures.Crashes, true);
consent.Add(ConsentFeatures.Events, false);
consent.Add(ConsentFeatures.Location, true);

//changing consent
Countly.Instance.SetConsent(consent);

Used storage

Cached requests and other SDK relevant information is stored in files in a named folder. All platform targets except .net40 call that folder "countly", .net40 calls that folder "countly_data".

All platform targets except .net35 will use (IsolatedStorage)[https://docs.microsoft.com/en-us/dotnet/standard/io/isolated-storage] for that. .net35 will store that named folder in the same folder as the executable by default.

If there are permission limitations for your app targeting .net35, then there is a call where you can change the path for the named storage folder. You can change that by using this:

Countly.SetCustomDataPath("C:\path\to\new\folder\");