Getting Started with SDKs


Countly provides various functionality in different SDKs targeted for mobile, web, desktop, and server-to-server use cases. For a feature comparison in all SDKs, please check this table.

There are common concepts in all Countly SDKs, and this document is intended to be a universal getting started guide without getting into the implementation details of individual SDKs. To get more information on platform-specific implementation, please refer to the documentation of the SDK of your choice.

User/device identification

By default, Countly generates an anonymous identifier to uniquely identify a device or browser. The total users metric for any period is based on a unique number of device ids the Countly Server receives requests from. Similarly, users list in User Profiles. The section lists anonymous devices from which the Countly Server is receiving data. All data originating from a single device, including sessions, events, views, and crashes, are grouped under these individual profiles since all the data is tagged with the originating device id.

Most Countly SDKs, including iOS, Android, React Native, Flutter, and Web, offer a mechanism to change/update this default device id for cases where you already have a better identifier, such as an email address or account id or you get this information at some point in user journey such as after user logs into your application. For an in-depth analysis of different device/user identification strategies, please check out this post.

Deciding on custom user properties

User properties play an important role not only in reporting but also in various other cases, such as personalizing push notifications and creating conditional remote configuration variables.

Most Countly SDKs send some user properties together with the session request triggered automatically when the app is launched, the user lands on a website, or manually in some cases, such as server-to-server SDK usage. These properties, which we call default user properties, are metadata, including but not limited to the app version, device, platform, and platform version.

Furthermore, there are some reserved user properties that you can choose to set, including name, email, organization, gender, and age if you choose to store PII (personally identifiable information) in Countly.

Custom user properties are similar in logic to default and reserved user properties in the sense that this information is stored at the user profile level. All the data (sessions, events, views, crashes, etc.) originating from a user will get tagged with a historical snapshot of default, reserved, and custom user properties and will be available to be used in reporting and features such as Cohorts, Funnels, Drill, Retention, and Formulas.

Custom user properties consist of key-value pairs, where the value can be a string, number, boolean, or array. There are various modifiers available in the SDKs, such as 'set,' 'set once,' 'push unique,' 'increment,' and 'multiply' to update these as needed. For example, you can store account levels of your users in an accountType custom user property that can take values Basic or Premium to later on filter & segment all reports based on the account type of your customers.


An "event" in Countly generally represents one of the following:

  • An action of the user, such as an interaction with a single UI element or set of elements.
  • An important milestone the user reaches after completing other actions, such as completing an application or onboarding process. 
  • A transaction that takes place after one or more actions of the user, such as a backend API returning a result.

It is important to note that events aren't designed only to track simple user interactions such as "user clicked this button." The way you define events in your app determines the depth of insights you can get from Countly. Tracking everything you possibly can or tracking very little is equally bad. An ideal strategy is collecting the needs of various departments in your organization that'll take advantage of Countly. As a common example;

  • The Product team will want to check feature usage; they will need multiple events that show how users interact with various application features.
  • The customer experience & success team will want to understand the paths users go through (such as during onboarding) and get stuck in and will need customized events as milestone indicators.
  • The Engineering team will want to get transactions & statutes that are created after users' interaction with the UI layer. Thus, they'll need events or event segments that they can take advantage of.
  • CXOs and managers will want to see higher-level metrics or KPIs; thus this higher-level data should exist either as dedicated events or as individual ones to be used while constructing complex metrics using Formulas.

In its most complex form (there can, of course, be additional segments), an event's JSON representation looks like below. The only mandatory fields are key and count which are set when you call the recordEvent function in any given SDK. Optional sum property is useful when you would like to store an extra numerical value for an event; in the below example, we used it to store kilometers for a journey. The duration property represented as dur can be explicitly set, or you can take advantage of the timed events concept available in most SDKs.

"key": "Journey",
"count": 1,
"sum": 100,
"dur": 3600,
"segmentation": {
"Route Type": "Fastest"

Now let's dive into event segments and strategies you can follow.

Deciding on event segments

Segments are properties that add further detail and meaning to an event. Segments are important since, most of the time, you aren't only interested in how many times some general action happened but also will need to dig deeper and filter certain cases or group occurrences by different nuances of the action.

From our event sample in the above section, thanks to the Route Type event segment, you can not only see overall journeys taking place but also see how many journeys were planned with the fastest, shortest, or eco route types offered in the app. Furthermore, plugins like Cohorts, Funnels, Drill, and Formulas these event segments will be available for use cases such as;

  • Filter events where Route Type = Eco using Drill.
  • Construct three different funnels where the final step is the Journey event in all but filtered to be Route Type = Eco, Route Type = Fastest, and Route Type = Shortest.
  • Create a behavioral cohort of users who did have a Journey with Route Type = Eco at least two times in the last 30 days (these are our eco-friendly personas, which we can target using remote config and automated push notifications).
  • Construct two formulas in which you calculate the average kilometers driven per journey for Route Type = Shortest and Route Type = Fastest.

As you can tell from the above reporting examples, event segment selection is an important part of your success with reporting & visualization in Countly.

Acquiring your application key and server url

Acquiring the application key

Also referred to as "appKey" or "app_key" as shorthand, the application key is used to identify the application for which the information has been gathered by the SDK. It is also tracked. You receive this value by creating a new application in Countly and accessing it on 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.


Acquiring the server URL

This is the domain from which you are accessing your Countly server. During your SDK initialization, you'll see a value such as 'url', 'server url,' or something similar that you need to fill in. You have to fill that value with the IP or hostname of your server. For example, if you have Countly installed on, then inside the SDK, you will need to write , if the SSL configuration is complete, or if there is no SSL configuration. If there is a server name associated with your IP, that server name may also be used instead (e.g.

Handling login/logout in your app

For a lot of apps, there is a login option. This allows you to confirm the identity of your users by cross-referencing them with your systems. That also adds two complications. First, multiple users can use the same app on the same device. The generated data would need to be assigned to the relevant user; therefore, the device ID needs to be changed. Second, the same user can log in to multiple devices. Therefore you need to use the same device ID on all of that user's devices. To achieve that, you would have an internal ID of your system or a derivative value that you can reliably generate.

The first time you initialize a Countly SDK, you would allow the SDK to generate the device ID. When the user logs in to your app, you will change the device ID to the new ID that you generate. If this is the first time the user logs in, we recommend that you change the device ID with merging. You would also want to change the device ID without merging on any follow-up logins. This way, you can assign the events generated by the user before the first login to the user that logs in.

When a user logs out, you have two options. First, you would not change the device ID. This way, you would also assign any follow-up events to the last user signed in, and those events would be sent as they happen. Second, if the SDK supports temporary ID mode; you can enter that when logout happens. This way, you would assign follow-up events to the user who would sign in next. The downside to the temporary ID approach is that no events would be sent while the user is not logged in. Both of these approaches not only solve a server-side performance issue but also eliminate the issue of inflated user counts. We recommend you choose the first logout option.

A key SDK feature that allows you to do this is the ability to see the device ID type. The two important things that you want to differentiate are if the ID is generated by the SDK or if it's a custom ID provided by you. If the ID is generated by the SDK, then, you can assume that the user has not logged in before and when changing the device ID, you need to do that with merging. If the device ID is a custom one, then you can assume that you have already changed the ID before and need to perform the current change without merging.

Here are a few sample login implementations of this flow:


Java Kotlin
public void Login() {
  String newId = "SomeValue";
  if (Countly.sharedInstance().deviceId().getID().equals(newId)) {
  if (Countly.sharedInstance().deviceId().getType() == DeviceIdType.DEVELOPER_SUPPLIED) {
    // an ID was provided by the host app previously
    // we can assume that a device ID change with merge was executed previously
    // now we change it without merging
  } else {
    // SDK generated ID
    // we change device ID with merge so that data is combined


Objective-C Swift
+ (void)login
CLYDeviceIDType deviceIDType = [Countly.sharedInstance deviceIDType];
if([deviceIDType isEqualToString:CLYDeviceIDTypeCustom])
[Countly.sharedInstance setNewDeviceID:@"usersNewID" onServer: NO];
[Countly.sharedInstance setNewDeviceID:@"usersNewID" onServer: YES];


Async Sync
function login() {
if(Countly.get_device_id_type() === Countly.DeviceIdType.DEVELOPER_SUPPLIED) {
/*change ID without merge as current ID is Dev supplied, so not first login*/
Countly.q.push(['change_id', "newID", false]);
} else {
/*change ID with merge as current ID is not Dev supplied*/
Countly.q.push(['change_id', "newID", true]);

Using the Countly SDK's with iOS and Android widgets and watches

With mobile devices, there are three different modalities that a user can interact with phone app, phone widget, and watch app. When designing a product that spans all three worlds, the goal is normally to track the user's lifecycle across all of them.

To perform this cross-modality tracking, care must be given that tracking is performed with the same device ID across all of them. If the device ID to which the event or session is attributed would not be the same across all devices and modalities, then the same user would be counted as a separate person on one of them.

This also means that if the user's device ID changes, this change needs to be synchronized across all modalities/apps.

This can be achieved in two general approaches:

  1. Performing data recording at each location separately - each modality integrates, configures, and initializes the Countly SDK separately. Device ID synchronization needs to be performed manually across all modalities. This would be accomplished either by using some platform-provided method to perform direct communication or using an external device (for example, a server) to perform a centralized exchange. Alternatively, every modality needs a way to create the same device ID without direct cross-synchronization.
  2. Performing data recording at a central location and proxying data recording from each non-app modality eliminates the need for synchronization, as only one instance of the SDK is initialized and configured. Device ID changes are immediately taken into account when they happen. Since cross-device recording is centralized, views and sessions must be recorded manually. The main issue with this approach is that there will be times when the main app might be out of reach for proxy recording or might not be running.

To differentiate from which modality the event came from, you can use a custom segmentation value that shows that. Every unique value would indicate a separate modality.

Notes for native iOS integration

The general recommendation is to have Countly integrated into each separate modality as that seems to present the least amount of issues. If the modalities used are from the same developer account, then an internal communication channel should be available to them. If they are not on the same developer account, an outside synchronization mechanism will need to be used.

For additional integration details, you will also have to look at this section.

Notes for native Android integration

Due to the way the SDK is currently designed, integrating the SDK in a widget will cause crashes. Therefore the recommendation is to proxy the tracking requests to the host application. Shared preferences could potentially be used to achieve this.

The SDK would be directly integrated with the watch modality, and then synchronization would be done with shared preferences.

Notes for Flutter integration

If you have a Flutter app, there doesn't seem to be an easy way to integrate other modalities. To achieve that, you would need to create them using the native platform languages and integrate the native Countly SDKs. In that case, the recommendations from the previous sections would apply.

How to validate your Countly integration?

After you have integrated the Countly SDK into your app or website, to the best of your ability, whether you see some data or not in your Countly server, you should normally verify your integration by checking if everything is working as expected, both on your Countly server and your app/website. To have the most optimized verification process, we recommend you go through the following steps for these cases of integration validation and also for debugging if you are seeing partial or no data at all on your server.

1. Check SDK logs

As part of the process of integration verification, you would want to enable logging into the SDK and have a look at the printed-out messages. If there were a warning, errors, or deprecation messages, it would indicate potential problems and action items that need to be fixed. Logging can be enabled during the SDK initialization, and the way you do that differs slightly from SDK to SDK. For specifics on how to enable it, you would want to check the documentation of the specific SDK that you are using from here.

After enabling SDK side logging, you would want to run your app or website and check the debug messages that are printed in the respective console. The specific location of that would change depending on the platform and SDK.


Check if requests are being created - this means you need to check whether you are calling SDK methods to actually send information to the server and that the SDK has been implemented correctly.

Also, check if requests fail or are successfully sent to the server because if they fail, maybe the server is not reachable from this specific network, or you made a mistake when providing the URL to the server.

2. Check Incoming Data Logs

Next, you would want to verify that your Countly server is receiving data from Utilities > Incoming Data Logs. Should there be an issue, the request logs usually state what this problem is about, why the request was not processed, or why incoming data may be incorrect - such as sending data for the incorrect app type, sending duplicate requests, incorrectly setting up parameter tampering, etc.


3. Make sure you have the correct configuration

Here the most important thing is to verify if your 'app_key' and 'URL' values are entered correctly. For more information on making sure that you are using your correct 'app_key' and server URL, you can check out the following section here.

4. Check your Countly server

If you have checked your SDK logs and everything seems to be working fine in your app or website, it is time to check Countly if the planned data is recorded as expected. As a simple test, you can simply open User Profiles in Countly to see if your app/website was able to connect and recognized as a user in your Countly server. If it is, you are good to go, and you can stop here on the list.


In case it seems like some data is not being recorded, it can be due to some requests being rejected related to problems with the checksum, or sometimes requests might be dropped if there are filtering rules set to do that. Sometimes filtering rules target more things than planned by accident. For debugging those issues and others, keep reading.

5. Check the server for errors

Check Management > Logs > Api Log for errors. Chances are, if there is a problem/bug with a specific plugin processing information, there would be new errors in the logs.


6. Check plugins

Some plugins that might be necessary to process data and provide functionalities you want might not be activated, or you might have accidentally disabled them. You can check your plugins' status from Management > Feature Management


7. Check Filtering rules

Events or requests may be blocked. In this case, check Main menu> Utilities > Filtering rules to see whether there are any rules that block events or any requests.


8. Check event limits

The event name limit may be exceeded (the limit is 100, by default), and may be adjusted under Management > Settings > API > Data Limits> Max unique event key.


9. Check checksum

Some SDKs provide an option to send a checksum along the request data to prevent data breaches by a middleman. If you have set a salt for checksum in your SDK but did not set it at your server or mistyped it, and vice-versa, you should check your salt value from Management > Applications > Salt for checksum.


10. Check time zone

Your time zone may be different from the application’s time zone, explaining why it takes some time for you to be able to see events on the graph, something that should be available to you without delay. You can edit your time zone from Management > Applications > Edit > Select Time Zone.


How long does it take for my data to show up on Countly?

When you are checking Countly and sending events from your app or website, you might realize that sometimes there is a delay for the data to show up there. This is an expected behavior stemming from the internal logic of the Countly SDKs and the potential server-side calculations.

SDK Side Processes

In some cases, there might just be a connection issue. Either the user is offline or unable to reach your server (due to server maintenance or other issues). Thus they would not be able to send data to the server. If, during this loss of connection, the SDK is not able to perform any network activity, it will wait for a while before reattempting the upload of recorded information. By default, this delay is 60 seconds (can be changed during init) and is tied to the session update tick interval.

The second aspect that can influence this is the event queue. Before we send the recorded events to the server, we try to cache them to optimize the networking. They are cached until their amount exceeds the threshold (by default 100, but can be configured), or the session update tick happens, or some other internal trigger happens.

Server Side Processes

In addition to this, there can be server-side calculations that can add additional delay. Depending on where you are expecting the changes to show up, the types and the length of the calculations involved would differ. For example, a cohort can take minutes up to hours to process before showing up on Countly. But most data would show up within seconds after reaching your Countly Server.

Is my SDK version compatible with my server?

If you have checked your Countly server and SDK versions, you might have noticed that they most likely do not match. Due to the way our development is structured, our Countly server releases happen more often than any single SDK. Usually, this will lead you to see that your server version is higher than your SDK version, and that is fine.

Our guidelines are that the major version of your server should be the same or higher than the major version of the SDK you are using. Our versioning scheme for our server releases and SDKs has three numbers separated by dots, something like "22.02.3". The first two numbers are what we call the major version, and those are the ones that you should be paying attention to ("22.02.X").

Finding SDK Logs

Ensure you have enabled SDK logs before proceeding with this process. For guidance on how to enable logs, refer to the SDK documentation's "Logging" or "Debug Mode" section.

Apple Devices:

  1. Launch your application through Xcode.
  2. Access the Output tab (annotated as 1).
  3. Filter the logs by typing in "countly" (annotated as 2).


Android Devices

  1. Run your application on Android Studio.
  2. Open the Logcat tab (annotated as 1).
  3. Filter the logs by typing in "countly" (annotated as 2).


Web browser:

  1. Open your website in a browser.
  2. Open the developer tools (typically by pressing F12).
  3. Select the Console tab (annotated as 1).
  4. Enable all log levels to view the SDK logs (annotated as 2).


Looking for help?