Windows (20.11.0)

Follow

This document explains how to install Countly SDK for Windows desktop applications. It applies to version 20.11.0.

Minimum Windows version

The Countly Windows SDK supports the following operating systems and .NET 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

Older documentation

To access the documentation for version 20.05 click here.

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 sample app

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

SDK Integration

Minimal Setup

Before you can use any Countly functionality, 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);

appKey - (Mandatory) The “App Key” for the app that you created on the Countly server. Example: 124qw3er5u678qwef88d6123456789qwertyui123.

serverUrl - (Mandatory) The URL of the Countly server where you are going to post your requests. Example: https://try.count.ly/

Note: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.

Providing the application key

Also called "appKey" as shorthand. The application key is used to identify for which application this information is tracked. You receive this value by creating a new application in your Countly dashboard and accessing it in its application management screen.

Note: Ensure you are using the App Key (found under Management -> Applications) and not the API Key. Entering the API Key will not work.

Providing the server URL

If you are using Countly Enterprise trial servers, use https://try.count.lyhttps://us-try.count.ly or https://asia-try.count.ly It is basically the domain from which you are accessing your trial dashboard.

If you use both Countly Lite and Countly Enterprise, use your own domain name or IP address, such as https://example.com or https://IP (if SSL has been set up).

SDK logging / debug mode

In order to make sure that requests to Countly are sent correctly, you need to enable logging using the 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 into the inner workings of the SDK.

SDK data 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 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\");

SDK notes

Additional info for Windows Store project setup

Windows Store build has been removed

The following section of documentation will be removed soon

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();
}

Additional info for UWP project setup

It's possible to register a unhandled crash handler during SDK initialization. To do that, you need to provide a link to your application.

var cc = new CountlyConfig
{
  serverUrl = "SERVER_URL",
  appKey = "APP_KEY",
  appKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXX
  appVersion = "1.2.3",
  application = referenceToApplication //provide link to your application
};

await Countly.Instance.Init(cc);

Crash reporting

Automatic crash handling

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.

Handled exceptions

To log handled exceptions, which are not fatal, use Countly.RecordException; the 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.

Dictionary<string, string> customInfo = new Dictionary<string, string>
{
{ "customData", "importantStuff" }
};

Countly.RecordException(ex.Message, ex.StackTrace, customInfo);

Crash breadcrumbs

Throughout your app, you can leave crash breadcrumbs Mandatory that would describe 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.AddBreadCrumb("breadcrumb");

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.

Recording events

Here is a quick way to record an event:

Countly.RecordEvent("event-key");

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 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);

Sessions

Manual 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 the entry point of the app.

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

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

That time is tracked using an 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);

View tracking

Manual view recording

The SDK provides a call to record views in your application. More information about how to use them can be found here. You only need to provide the name for the view.

Countly.Instance.RecordView("Some View");

Device ID management

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 its 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.

Device ID generation

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

  • cpuId - [net35, net40] (we recommend against using this) uses the OS-provided CPU id info to generate a hash that is used as an 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 are not guaranteed to be unique and generate the same id and therefore device id conflicts
  • 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 an 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 an 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);

Changing device ID

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);

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

After SDK initialization, you can set location info.

//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 an empty string.

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

Disabling location

Users might want to opt-out of location tracking. To do so call:

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

This will also erase all location info server side.

User Profiles

This feature is available with Countly Enterprise subscription. For information about User Profiles, review this documentation.

Setting predefined values

The 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.
  • Picture: 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.

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

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

Example:

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

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 can provide custom properties for user using Custom object

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

Setting User picture

Additionally, you can upload a 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.

User consent

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.

Setup during init

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 the consent status of a feature is changed, that change will be sent to the Countly server.

Consent for features is not persistent and will have to be set every time while initializing countly. Therefore the storage and persistence of given consent fall on the SDK integrator.

Feature names in this SDK are stored as an 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 events to the server
  • location - allow sending location information
  • crashes - allow tracking crashes, exceptions, and errors
  • users - allow collecting/providing user information, including custom properties

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.

//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);

Consent can also be changed 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);

Other features

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:
- Screen resolution
- Screen density
- OS name
- OS version
- App version
- Locale identifier

* 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 resolution
- App version
- Time of the crash
- Crash stack trace
- Error description
- Total RAM

- If there is a network connection

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.

Comments

0 comments

Please sign in to leave a comment.