This documentation is for the Countly React Native SDK version 26.1.X The SDK source code repository can be found here.
Click here, to access the documentation for older SDK versions.
This is the Countly SDK for React Native applications. It features 'bridging', meaning it uses Countly Android and iOS SDKs underneath.
For this reason, Countly Android and iOS SDK system requirements are also extended to React Native SDK:
For iOS builds, this SDK requires a minimum Deployment Target iOS 10.0 (watchOS 4.0, tvOS 10.0, macOS 10.14), and it requires Xcode 13.0+.
For Android builds, this SDK requires a minimum Android version of 5.0 (API Level 21).
This SDK also depends on the react-native library for communicating with the native side. While it can possibly work with older versions, the currently supported react-native versions are 0.60.0 and up and New Architecture support for Android starts from this version.
To examine the example integrations, please have a look here.
Adding the SDK to the Project
Run the following snippet in the root directory of your React Native project to install the npm dependencies and link native libraries.
# Include the Countly Class in the file that you want to use. npm install --save https://github.com/Countly/countly-sdk-react-native-bridge.git # OR npm install --save countly-sdk-react-native-bridge@latest # for non push version countly-sdk-react-native-bridge-np # Linking the library to your app cd ios pod install cd ..
SDK Integration
Minimal Setup
We will need to call initWithConfig in order to set up our SDK. This method should only be called once during the app's lifecycle and should be done as early as possible. Your main app component's componentDidMountmethod may be a good place.
import Countly from 'countly-sdk-react-native-bridge';
import CountlyConfig from 'countly-sdk-react-native-bridge/CountlyConfig';
// create Countly config object
const countlyConfig = new CountlyConfig("Server_URL", "YOUR_APP_KEY");
await Countly.initWithConfig(countlyConfig); // Initialize the Countly SDK with config.
Please check here for more information on how to acquire your application key (APP_KEY) and server URL.
After initWithConfig has been called once, you may use the commands in the rest of this document to send additional data and metrics to your server.
If you are in doubt about the correctness of your Countly SDK integration you can learn about the verification methods from here.
SDK Logging
The first thing you should do while integrating our SDK is enable logging. If logging is enabled, then our SDK will print out debug messages to your IDE's console about its internal state and encountered problems.
Call setLoggingEnabled on the config object to enable logging:
// create Countly config object
const countlyConfig = new CountlyConfig("https://your.server.ly", "YOUR_APP_KEY");
// ...
countlyConfig.setLoggingEnabled(true); // Enable countly internal debugging logs
await Countly.initWithConfig(countlyConfig); // Initialize the countly SDK with config.For more information on where to find the SDK logs you can check the documentation here.
Crash Reporting
The Countly SDK has the ability to collect crash reports, which you may examine and resolve later on the server.
Automatic Crash Handling
With this feature, the Countly SDK will generate a crash report if your application crashes due to an exception and will send it to the Countly server for further inspection.
If a crash report cannot be delivered to the server (e.g. no internet connection, unavailable server, etc.), then the SDK stores the crash report locally in order to send the report again, when the connection to server is restored.
You will need to call the following method before calling initWithConfig in order to activate automatic crash reporting.
// create Countly config object
const countlyConfig = new CountlyConfig("https://your.server.ly", "YOUR_APP_KEY");
// ...
countlyConfig.enableCrashReporting(); // Enable crash reports
await Countly.initWithConfig(countlyConfig); // Initialize the countly SDK with config.Automatic Crash Report Segmentation
You may add a key/value segment to crash reports. For example, you could set which specific library or framework version you used in your app. You may then figure out if there is any correlation between the specific library or another segment and the crash reports.
Use the following function for this purpose:
var segment = {"Key": "Value"};
Countly.setCustomCrashSegments(segment);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 with the following command:
Countly.logException(stack, nonfatal, customSegments);
The method logExceptiontakes a string for the stack trace, a boolean flag indicating if the crash is considered fatal or not, and a segments dictionary to add additional data to your crash report.
Below are some examples that how to log handled/nonfatal and unhandled/fatal exceptions manually.
1. Manually report handled exception
Countly.logException("STACK_TRACE_STRING", true);2. Manually report handled exception with segmentation
Countly.logException("STACK_TRACE_STRING", true, {"_facebook_version": "0.0.1"});3. Manually report fatal exception
Countly.logException("STACK_TRACE_STRING", false);4. Manually report fatal exception with segmentation
Countly.logException("STACK_TRACE_STRING", false, {"_facebook_version": "0.0.1"});Crash Breadcrumbs
Throughout your app, you can leave crash breadcrumbs which 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.
Following the command adds crash breadcrumb:
Countly.addCrashLog(String record)
Native C++ Crash Reporting
If you have C++ libraries in your React Native Android app, the React Native Bridge SDK allows you to record possible crashes in your Countly server by integrating the sdk-nativedeveloped within our Android SDK. Find more information here.
As this feature is optional, you will need to do some changes in your react native android project files, to make it available.
Go to YOUR_REACT_NATIVE_PROJECT_PATH/android/app/build.gradleand add the package dependency (please change the LATEST_VERSION below by checking our Maven page):
dependencies {
implementation 'ly.count.android:sdk-native:LATEST_VERSION'
}Then call Countly.initNative() method as early as possible in your react native android project to be able to catch setup time crashes, it should be preferably in the "onCreate" callback of the Application class.
You may find MainApplication.java at this path:
YOUR_REACT_NATIVE_PROJECT_PATH/android/app/src/main/java/com/PROJECT_NAME
// import this in your Application class import ly.count.android.sdknative.CountlyNative; // call this function in "onCreate" callback of Application class CountlyNative.initNative(getApplicationContext());
getApplicationContext() is needed to determine a storage place for minidump files.
Sending crash dump files to the server will be taken care of by the SDK during the next app initialization. We also provide a Gradle plugin that automatically uploads symbol files to your server (these are needed for the symbolication of crash dumps). Integrate it into your React Native project as explained in the relevant Android documentation page.
This is what the debug logs will look like if you use this feature:
$ adb logcat -s Countly:V countly_breakpad_cpp:V # when Countly.initNative() is called D/countly_breakpad_cpp(123): breakpad initialize succeeded. dump files will be saved at /Countly/CrashDumps # when a crash occurs (you may trigger one by Countly.testCrash()) D/countly_breakpad_cpp(123): DumpCallback started D/countly_breakpad_cpp(123): DumpCallback ==> succeeded path=/Countly/CrashDumps/30f6d9b8-b3b2-1553-2efe0ba2-36588990.dmp # when app is run again after the crash D/Countly (124): Initializing... D/Countly (124): Checking for native crash dumps D/Countly (124): Native crash folder exists, checking for dumps D/Countly (124): Crash dump folder contains [1] files D/Countly (124): Recording native crash dump: [30f6d9b8-b3b2-1553-2efe0ba2-36588990.dmp]
Events
An Event is any type of action or data that you can send to a Countly instance, e.g. purchases, changed settings, view enabled, and so on. This way it's possible to get much more information from your application compared to what is sent from the SDK to the Countly instance by default.
Here are the details about the properties which you can send with an event:
-
eventNamename of the event at server (String) (mandatory) -
segmentationkey-value pairs that can be used to track additional information (Object) -
eventCountnumber of times this event occurred. Total count can be viewed at server (Number) -
eventSumany numerical data tied to an event. Total sum can be viewed at server (Number)
Data passed should be in UTF-8
All data passed to the Countly server via the SDK or API should be in UTF-8.
Recording Events
We will be recording a purchase event below. Here is a quick summary of the information with which each usage will provide us:
- 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.
1. Event key and count
Countly.events.recordEvent("Purchase", undefined, 1);2. Event key, count, and sum
Countly.events.recordEvent("Purchase", undefined, 1, 0.99);3. Event key and count with segmentation(s)
Countly.events.recordEvent("Purchase", { Country: "Germany" }, 1 )4. Event key, count, and sum with segmentation(s)
Countly.events.recordEvent("Purchase", { Country: "Germany" }, 1, 0.99)Those are only a few examples of what you can do with events. You may extend those examples and use Country, game_level, time_of_day, and any other segmentation that will provide you with valuable insights.
Timed Events
It's possible to create timed events by calling start and stop methods. This would calculate the duration between those two calls and record it as the duration of the event. However the start method only serves as a timer and unless the end method is called no event will be recorded.
//start a timed event
Countly.events.startEvent("Event name");
//wait some time
//end the event
Countly.events.endEvent("Event name");
You may also provide additional information when ending an event:
//start a timed event
Countly.events.startEvent("Event name");
//wait some time
//end the event
Countly.events.endEvent("Event name", { Country: "Germany", Age: "21" }, 1, 0.99);
You may cancel the started timed event in case it is not relevant anymore. Also restarting the app would cancel a started timed event.
//start a timed event
Countly.events.startEvent("Event name");
//wait some time
// cancels the timed event
Countly.events.cancelEvent("Event name");
// now this will not work
Countly.events.endEvent("Event name");Sessions
Automatic Session Tracking
This is enabled by default and tracks the user's session with respect to the app visibility.
The SDK will automatically handle all required requests (begin session, update session and end session).
Manual Session Tracking
If you need to control session lifetime yourself, enable manual session handling during initialization:
const countlyConfig = new CountlyConfig("https://your.server.ly", "YOUR_APP_KEY");
countlyConfig.enableManualSessionControl();
await Countly.initWithConfig(countlyConfig);After initialization, use the dedicated session interface:
Countly.sessions.beginSession(); Countly.sessions.updateSession(); Countly.sessions.endSession();
While a manual session is active, you can call Countly.sessions.updateSession() regularly to update the session time on the server.
Hybrid Mode
If you want to start and end sessions manually but let the SDK handle periodic update calls, enable hybrid mode during initialization:
const countlyConfig = new CountlyConfig("https://your.server.ly", "YOUR_APP_KEY");
countlyConfig.enableManualSessionControlHybridMode();
await Countly.initWithConfig(countlyConfig);After initialization, you only need to call Countly.sessions.beginSession() and Countly.sessions.endSession(). The SDK handles the update calls in between.
Content Zone
The Content Zone feature enhances user engagement by delivering various types of content blocks, such as in-app messaging, ads, or user engagement prompts by utilizing Journeys. These content blocks are dynamically served from the content builder on the server, ensuring that users receive relevant and up-to-date information.
Content support for Android platform is available only on API level 28 and above.
For learning how you can use Journeys & Content Builder to create In-App messages you can check this article.
Only thing you need to do to enable this feature and start fetching content from the server according to your Journeys, use the following method:
Countly.content.enterContentZone();
This call will retrieve and display any available content for the user. It will also regularly check if a new content is available, and if it is, will fetch and show it to the user.
Fine Tuning Content
Content checks happen every 30 seconds by default. This can be configured while initializing the SDK (minimum 15 seconds).
countlyConfig.content.setZoneTimerInterval(60); // in seconds
If you need to trigger a Journey and display its content after a specific user action you can use the method below to speed up the process:
Countly.content.refreshContentZone();
When you want to exit from the content zone and stop the SDK from checking for available content you can use this method:
Countly.content.exitContentZone();
To get informed when a user closes a content you can register a global content callback during SDK initialization:
countlyConfig.content.setGlobalContentCallback(callback);
Content Preview
If you want to preview a specific content directly, without entering the content zone, use:
Countly.content.previewContent("CONTENT_ID");Display Options
Content and feedback widgets are displayed in immersive mode by default. If you want the SDK to respect the safe area instead, choose a display option during initialization:
const countlyConfig = new CountlyConfig("https://your.server.ly", "YOUR_APP_KEY");
countlyConfig.content.setWebViewDisplayOption(Countly.webViewDisplayOption.SAFE_AREA);
await Countly.initWithConfig(countlyConfig);View Tracking
SDK exposes view tracking under Countly.views. You can enable automatic native view tracking or record views manually.
Automatic View Tracking
To track native screen transitions automatically, enable it during initialization:
const countlyConfig = new CountlyConfig("https://your.server.ly", "YOUR_APP_KEY");
countlyConfig.enableAutomaticViewTracking();
await Countly.initWithConfig(countlyConfig);If you want to exclude specific native screens, provide their class names during initialization. On Android these should be fully qualified activity names.
countlyConfig.setAutomaticViewTrackingExclusionList([ "com.example.DebugActivity", "com.example.InternalActivity", ]);
Manual View Recording
For custom flows, you can start views manually. Auto-stopped views end automatically when another auto-stopped view begins.
const viewID = await Countly.views.startAutoStoppedView("Home Screen");
const segmentedViewID = await Countly.views.startAutoStoppedView("Checkout", {
step: "shipping",
plan: "pro",
});Multi View Tracking
If you need multiple views to stay active at the same time, start them explicitly and stop them by name or by the returned view ID:
const feedViewID = await Countly.views.startView("Feed");
const modalViewID = await Countly.views.startView("Promo Modal", { campaign: "spring" });
// later
Countly.views.stopViewWithID(modalViewID, { result: "dismissed" });
Countly.views.stopViewWithName("Feed");
Countly.views.stopAllViews();Pausing and Resuming Views
You can pause and resume individual views by their IDs:
const viewID = await Countly.views.startView("Checkout");
Countly.views.pauseViewWithID(viewID);
// ...
Countly.views.resumeViewWithID(viewID);Adding Segmentation to Started Views
You can enrich an active view before it ends by adding or overriding segmentation values:
const viewID = await Countly.views.startView("Checkout");
Countly.views.addSegmentationToViewWithID(viewID, { step: "payment" });
Countly.views.addSegmentationToViewWithName("Checkout", { coupon: "SPRING" });Global View Segmentation
You can attach default segmentation to all views during initialization or update it at runtime:
const countlyConfig = new CountlyConfig("https://your.server.ly", "YOUR_APP_KEY");
countlyConfig.setGlobalViewSegmentation({ app_version: "1.0.0" });
await Countly.initWithConfig(countlyConfig);
Countly.views.setGlobalViewSegmentation({ region: "eu" });
Countly.views.updateGlobalViewSegmentation({ plan: "pro" });By default, manually recorded views are restarted automatically when the app returns to the foreground. If you manage that lifecycle yourself, disable the restart behavior during initialization:
countlyConfig.disableViewRestartForManualRecording();
To review the resulting data, open the dashboard and go to Analytics > Views
Device ID Management
Countly server identifies each user according to their device ID. Each request the SDK sends to the server includes this value. So the uniqueness of this value is important if you plan to change it.
The SDK generates a random UUID during the first initialization. If you want to override it you can use this config method:
countlyConfig.setDeviceID("newID");Retrieving Current Device ID
You can get the current device ID of the user with these calls:
const currentDeviceId = await Countly.deviceId.getID(); const currentDeviceIdType = await Countly.deviceId.getType();
You can use deviceId.getType method which returns a value identifying the current device ID type. The possible types are:
- DEVELOPER_SUPPLIED - device ID was supplied by the host developer.
- SDK_GENERATED - device ID was generated by the SDK.
- TEMPORARY_ID - the SDK is in temporary device ID mode.
Changing Device ID
To change the user's current device ID you can use this method:
Countly.deviceId.setID("newID");This method's effect on the server will be different according to the type of the current ID stored in the SDK at the time you call it:
-
If current stored ID is
SDK_GENERATEDthen in the server all the information recorded for that device ID will be merged to the new ID you provide and old user with theSDK_GENERATEDID will be erased. -
If the current stored ID is
DEVELOPER_SUPPLIEDorTEMPORARY_IDthen in the server it will also create a new user with this new ID if it does not exist.
If you need explicit control over whether the old and new IDs are merged on the server, use the method mentioned here instead.
Temporary Device ID
You may use a temporary device ID mode for keeping all requests on hold until the real device ID is set later.
To enable this when initializing the SDK, use the method below.
// create Countly config object
const countlyConfig = new CountlyConfig("https://your.server.ly", "YOUR_APP_KEY");
//...
countlyConfig.setDeviceID(Countly.TemporaryDeviceIDString); // Set temporary device ID
await Countly.initWithConfig(countlyConfig); // Initialize the countly SDK with config.
To enable a temporary device ID after initialization, use the method below.
Countly.deviceId.setID(Countly.TemporaryDeviceIDString);
As long as the device ID value is Countly.TemporaryDeviceIDString, the SDK will be in temporary device ID mode and all requests will be on hold, but they will be persistently stored.
When in temporary device ID mode, method calls for presenting feedback widgets and updating remote config will be ignored.
Later, when the real device ID is set using Countly.deviceId.setID("REAL_DEVICE_ID") or Countly.deviceId.changeID("REAL_DEVICE_ID", true), all requests which have been kept on hold until that point will start with the real device ID.
Device ID Generation
When the SDK is initialized the first time and no custom device ID is provided, a random UUID will be generated on both iOS and Android.
Push Notifications
Please first check our Push Notifications documentation to see how you can use this feature. Since Android and iOS handles notifications differently (from how you can send them externally to how they are handled in native code), we need to provide different instructions for these two platforms.
General Setup
Android and iOS devices require different setups to enable the push notifications. Android uses the setPushNotificationChannelInformation, whereas iOS uses the setPushTokenType method on the CountlyConfig object. Both of these methods must be called before initializing the SDK.
// create Countly config object
const countlyConfig = new CountlyConfig("https://your.server.ly", "YOUR_APP_KEY");
// Set the token types: DEVELOPMENT, PRODUCTION or ADHOC
countlyConfig.setPushTokenType(Countly.messagingMode.DEVELOPMENT);
// Initialize the countly SDK with config.
await Countly.initWithConfig(countlyConfig);
// create Countly config object
const countlyConfig = new CountlyConfig("https://your.server.ly", "YOUR_APP_KEY");
// Method to set the push channel name and description.
countlyConfig.setPushNotificationChannelInformation("Channel Name", "Channel Description");
// Initialize the countly SDK with config.
await Countly.initWithConfig(countlyConfig);
When you are ready to initialize Countly Push, call Countly.askForNotificationPermission() after initWithConfig, using the method below. This method will ask for permission, and send push token to Countly server.
Countly.askForNotificationPermission();
Push Notification Customization
Notification Accent Color
Currently, push notification customization is only supported for Android devices. You can only select the accent color of your notifications and provide a custom notification sound.
You can provide a color in hexadecimal color system to the CountlyConfig object with the setPushNotificationAccentColor method before the SDK initialization.
// Set notification accent color
countlyConfig.setPushNotificationAccentColor("#000000");Custom Sound
Currently custom sound feature is only available for Android.
To use a custom sound for your notifications in Android you should provide a path to your sound file and pass it as the first parameter of the askForNotificationPermission method.
// CUSTOM_SOUND_PATH is an optional parameter and currently only supported for Android.
Countly.askForNotificationPermission("CUSTOM_SOUND_PATH");We will use this custom sound path to create a soundUri and set the sound of notification channel.
If you would like to use a custom sound in your push notifications, they must be present on the device. They cannot be linked from the Internet.
We recommend to add the custom sound file in your Android project res/raw folder. Always create a "raw" folder by right clicking on Resources (res) folder and select New -> Android Resource Directory.
Your custom sound path will be like this after adding it in res/raw folder:
"android.resource://PACKAGE_NAME/raw/NAME_OF_SOUND_WITHOUT_EXTENSION";
For more information about custom push notification sounds in Android check this section of Android article.
Android Setup
Step 1: For FCM credentials setup please follow the instruction from this URL
Step 2: Make sure you have google-services.json from Firebase website
Step 3: Make sure the app package name and the google-services.json package_name matches.
Step 4: Place the google-services.json file inside android/app
Step 5: Use google services latest version from this link
Step 6: Add the following line in the file android/build.gradle
buildscript {
dependencies {
classpath 'com.google.gms:google-services:4.3.2'
}
}
Step 7: Add the following line in file android/app/build.gradle
// Add this at the bottom of the file apply plugin: 'com.google.gms.google-services'
Note: You need to take additional steps to handle multiple messaging services. If you are using other plugins for push notifications, please follow the instructions from this URL:
Handling multiple FCM services
Additional Intent Redirection Checks
Intent Redirection Vulnerability is an issue that lets your app allow malicious apps to access private app components or files. Google removes apps from Google Play that is susceptible to Intent Redirection Vulnerability. For Push Notifications, we are also using Intent Redirection in our SDK, so for that reason, we have also implemented additional Intent Redirection protection.
By default additional intent redirection is enabled for intent redirect security, you can disable the additional intent redirection with disableAdditionalIntentRedirectionChecks:
const countlyConfig = new CountlyConfig("https://your.server.ly", "YOUR_APP_KEY");
// ...
countlyConfig.disableAdditionalIntentRedirectionChecks(); // Disable intent redirection security
await Countly.initWithConfig(countlyConfig); // Initialize the countly SDK with config.
If these are enabled then the SDK will enforce additional security checks. More info can be found here.
If, for some reason, the 'activity name' does not start with the 'application package name' (for e.g if you are using Android Product/Build Flavors to create multiple apps with the same code base), then you need to provide the additional allowed class and package names for Intent Redirection manually.
You can set the allowed package and class names for Intent Redirection using this call:
// create Countly config object
const countlyConfig = new CountlyConfig("https://your.server.ly", "YOUR_APP_KEY");
// ...
countlyConfig.configureIntentRedirectionCheck(["MainActivity"], ["com.countly.demo"]);
// configure redirection check
await Countly.initWithConfig(countlyConfig); // Initialize the countly SDK with config.
iOS Setup
Push notifications are enabled by default for iOS, but if you wish to disable them, you can define the macro "COUNTLY_EXCLUDE_PUSHNOTIFICATIONS" in the project's preprocessor macros setting. The location of this setting may vary depending on the development environment you are using.
For example, in Xcode, you can define this macro by navigating to the project settings, selecting the build target, and then selecting the "Build Settings" tab. Under the "Apple LLVM - Preprocessing" section, you will find the "Preprocessor Macros" where you can add the macro "COUNTLY_EXCLUDE_PUSHNOTIFICATIONS" to the Debug and/or Release fields. This will exclude push notifications from the build.
For iOS push notification integration please follow the instructions from here
For React Native you can find CountlyNotificationService.h/m file under Pods/Development Pods/CountlyReactNative/CountlyNotificationService.h/m
Pro Tips to find the files from deep hierarchy:
- You can filter the files in the navigator using a shortcut ⌥⌘J (Option-Command-J), in the filter box type "CountlyNotificationService" and it will show the related files only.
- You can find the file using the shortcut ⇧⌘O (Shift-Command-O) and then navigate to that file using the shortcut ⇧⌘J (Shift-Command-J)
You can drag and drop both .h and .m files from Pod to Compile Sources.
Removing Push and Its Dependencies
Countly React Native SDK comes with embedded push notification capabilities. For the flavor without these features (like Firebase libraries), please check here.
Handling Push Callbacks
Use the method below to register a Push Notification callback after initializing the SDK.
Countly.registerForNotification(function(theNotification){
console.log(JSON.stringify(theNotification));
});To listen to notifications received and the click events, add the code below in AppDelegate.m
Add header files
#import "CountlyReactNative.h" #import <UserNotifications/UserNotifications.h>
Add this call [CountlyReactNative startObservingNotifications]; in didFinishLaunchingWithOptions: method to handle push notification receive and action callbacks when SDK is not initialized.
// For push notification received and action callbacks.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
[CountlyReactNative startObservingNotifications];
}Before @end add these methods
// Required for the notification event. You must call the completion handler after handling the remote notification.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary*)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
[CountlyReactNative onNotification: userInfo];
completionHandler(0);
}
// When app is killed.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse*)response withCompletionHandler:(void (^)(void))completionHandler{
[CountlyReactNative onNotificationResponse: response];
completionHandler();
}
// When app is running.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification*)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
[CountlyReactNative onNotification: notification.request.content.userInfo];
completionHandler(0);
}
Data Structure Received in Push Callbacks
Here is an example of how the data will be received in push callbacks:
Data Received for Android Platform:
{
"c.e.cc": "TR",
"c.e.dt": "mobile",
"Key": "value",
"c.i": "62b59b979f05a1f5e5592036",
"c.l": "https:\/\/www.google.com\/",
"c.m": "https:\/\/count.ly\/images\/logos\/countly-logo-mark.png?v2",
"c.li": "notify_icon",
"badge": "1",
"sound": "custom",
"title": "title",
"message": "Message"
}Data Received for iOS Platform:
{
"c": {
"i": "62b5b945cabedb0870e9f217",
"l": "https:\/\/www.google.com\/",
"e": {
"dt": "mobile",
"cc": "TR"
},
"a": "https:\/\/count.ly\/images\/logos\/countly-logo-mark.png"
},
"aps": {
"mutable-content": 1,
"alert": {
"title": "title",
"subtitle": "subtitle",
"body": "Message"
},
"badge": 1,
"sound": "custom"
},
"Key": "value"
}User Location
Countly allows you to send geolocation-based push notifications to your users. By default, the Countly Server uses the GeoIP database to deduce a user's location.
Set User Location
If your app has a different way of detecting location, you may send this information to the Countly Server by using the countlyConfig.setLocation orCountly.setLocation methods.
We recommend using the countlyConfig.setLocation method before initialization to send location. This includes:
-
countryCodea string in ISO 3166-1 alpha-2 format country code -
citya string specifying city name -
locationa string comma-separated latitude and longitude -
IPa string specifying an IP address in IPv4 or IPv6 formats
// create Countly config object
const countlyConfig = new CountlyConfig("https://your.server.ly", "YOUR_APP_KEY");
//...
var countryCode = "us";
var city = "Houston";
var latitude = "29.634933";
var longitude = "-95.220255";
var ipAddress = "103.238.105.167";
countlyConfig.setLocation(countryCode, city, latitude + "," + longitude, ipAddress);
// Set location
await Countly.initWithConfig(countlyConfig); // Initialize the countly SDK with config.
Geolocation recording methods may also be called at any time after the Countly SDK has started. To do so, use the setLocation method as shown below.
// Example for setLocation var countryCode = "us"; var city = "Houston"; var latitude = "29.634933"; var longitude = "-95.220255"; var ipAddress = "103.238.105.167"; Countly.setLocation(countryCode, city, latitude + "," + longitude, ipAddress);
Disable Location
To erase any cached location data from the device and stop further location tracking, use the following method. Note that if after disabling location, the setLocationis called with any non-null value, tracking will resume.
//disable location tracking Countly.disableLocation();
Remote Config
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.
In the React Native bridge, Remote Config is exposed through the async Countly.remoteConfig interface.
Manual Remote Config Download
There are three ways for manually requesting a remote config update:
- Manually updating everything
- Manually updating specific keys
- Manually updating everything except specific keys.
These calls are async. Normal runtime issues are logged by the SDK and do not throw back into your app code.
await Countly.remoteConfig.update(); await Countly.remoteConfig.updateForKeysOnly(["aa", "bb"]); await Countly.remoteConfig.updateExceptKeys(["aa", "bb"]);
Getting Remote Config Values
To request a stored value, call Countly.remoteConfig.getValue with the specified key.
const data = await Countly.remoteConfig.getValue("KeyName");If the key does not exist or the value cannot be resolved, this call returns null.
Clearing Stored Remote Config Values
At some point, you might like to erase all the values downloaded from the server. Use:
await Countly.remoteConfig.clearValues();
User Feedback
There are several ways to receive user feedback: the Star Rating Dialog and the Feedback Widgets (Survey, NPS, Rating).
In Countly Lite, Star Rating Dialog allows users to give feedback of a rating from 1 to 5. In Countly Enterprise, Feedback Widgets (Survey, NPS, Rating) allow for even more textual feedback from users.
Star Rating Dialog
The Star-rating integration provides a dialog for getting user feedback about an application. It contains a title, a simple message explaining its purpose, a 1 through 5-star meter for getting users' ratings, and a dismiss button in case the user does not want to give a rating.
This star rating has nothing to do with Google Play Store ratings and reviews. It is simply for getting brief user feedback to be displayed on the Countly dashboard. If the user dismisses the star-rating dialog without giving a rating, the event will not be recorded.
Countly.showStarRating();
The star-rating dialog's title, message, and dismiss button text may be customized through the setStarRatingDialogTexts method.
const countlyConfig = new CountlyConfig("https://your.server.ly", "YOUR_APP_KEY");
// ...
countlyConfig.setStarRatingDialogTexts("Custom title", "Custom message", "Custom dismiss button text");
// Set dialog texts
await Countly.initWithConfig(countlyConfig); // Initialize the countly SDK with config.
Feedback Widget
Feedback Widgets is a Countly Enterprise plugin.
It is possible to display 3 kinds of Feedback widgets: NPS, Surveys and Rating. All widgets are shown as webviews, and the same methods are used to present them.
For more detailed information about Feedback Widgets, you can refer to here.
Before any feedback widget can be shown, you need to create them in your Countly dashboard.
To show feedback widgets you should use the direct presentation helpers shown below. They show the first available widget with the given selector and, if none matches, a widget of that type. You can optionally provide separate callbacks for when the widget is shown and when it is closed.
Countly.feedback.presentNPS(nameIDorTag?: string, widgetShownCallback?: WidgetCallback, widgetClosedCallback?: WidgetCallback): void Countly.feedback.presentSurvey(nameIDorTag?: string, widgetShownCallback?: WidgetCallback, widgetClosedCallback?: WidgetCallback): void Countly.feedback.presentRating(nameIDorTag?: string, widgetShownCallback?: WidgetCallback, widgetClosedCallback?: WidgetCallback): void
Countly.feedback.presentSurvey("onboarding", function() {
console.log("Widget shown");
}, function() {
console.log("Widget closed");
});If you need a more complex logic to display your widgets you can check extended documentation from here.
Manual Reporting
If you have a custom UI where you collect user feedback or you already have some feedback data in your system you can report that information to specific feedback widgets that you have created in your dashboard through the SDK manually.
This process consists of three steps:
- Retrieving the list of available widgets and picking one. This is the same initial step while using the feedback widgets and reuses the same call to retrieve them.
- Download widget data from the server (here you would use a widget you pick at step one).
- Report the feedback result (for that single widget according to the data from the previous step).
To get your available widget list, use the call below.
// with callback
Countly.feedback.getAvailableFeedbackWidgets(function(retrivedWidgets, error){
if (error != null) {
console.log("Error : " + error);
}
else {
console.log(retrivedWidgets)
}
});
//OR async
Object response = await Countly.feedback.getAvailableFeedbackWidgets();
if (!response.error) {
// pick a widget from response.data array
const widgetInfo = response.data[0];
}To download the widget data use:
// with callback
Countly.feedback.getFeedbackWidgetData(widget,function(retrivedWidgetData, error){
if (error != null) {
console.log("Error : " + error);
}
else {
console.log(retrivedWidgetData)
}
});
//OR async
Object response = await Countly.feedback.getFeedbackWidgetData(widget);
if (!response.error) {
// check the response.data Object to learn what is needed to be reported
const widgetData = response.data;
}Then after these two steps you would need to create a widgetResult Object and pass it to the function below with the other information you have gathered so far. You can check this in-depth guide to learn how to form this object:
Countly.feedback.reportFeedbackWidgetManually(widgetInfo, widgetData, widgetResult);
User Profiles
User Profiles is a Countly Enterprise plugin and built-in Flex.
You can provide Countly any details about your users. This will allow you to distinguish the user on the "User Profiles" tab beyond the device ID of the user. For more information, please check the User Profiles documentation.
While the device ID serves as the unique identifier for a user—much like DNA—the User Profile functions as the 'attire' that provides a more personalized, human-readable distinction between users. The backend relies solely on the device ID for identification purposes. However, User Properties allow you to customize and differentiate users in a more meaningful way. Importantly, modifying the User Properties does not affect the underlying user data or their historical information.
Setting User Properties
If a property is set as an empty string, it will be deleted on the server side.
Custom Values
Custom user properties are any arbitrary values that you would like to store under your user's profile.
var data = {};
data.customValueA = "customVal_1";
data.customValueB = "customVal_2";
// ...
Countly.setUserData(data);Predefined Values
Predefined user properties are a set of default keys that are commonly used in visitor data collection.
The keys for predefined user data fields are as follows:
| Key | Type | Description |
|---|---|---|
| name | String | User's full name |
| username | String | User's nickname |
| String | User's email address | |
| organization | String | User's organization name |
| phone | String | User's phone number |
| picture | String | URL to avatar or profile picture of the user |
| picturePath | String | Local path to the user's avatar or profile picture |
| gender | String | User's gender |
| byear | int | User's year of birth as integer |
Bellow you can see how these can be set:
var options = {};
options.name = "Nicola Tesla";
options.username = "nicola";
options.email = "info@nicola.tesla";
options.organization = "Trust Electric Ltd";
options.phone = "+90 822 140 2546";
options.picture = "http://www.trust.electric/images/people/nicola.png";
options.picturePath = "";
options.gender = "M";
options.byear = 1919;
Countly.setUserData(options);Modifying Data
Additionally, you can modify these custom values in various ways like increasing a number, pushing new values to an array, etc. You can see the whole range of operations below.
Countly.userData.setProperty("keyName", "keyValue"); //set custom property
Countly.userData.setOnce("keyName", 200); //set custom property only if property does not exist
Countly.userData.increment("keyName"); //increment value in key by one
Countly.userData.incrementBy("keyName", 10); //increment value in key by provided value
Countly.userData.multiply("keyName", 20); //multiply value in key by provided value
Countly.userData.saveMax("keyName", 100); //save max value between current and provided
Countly.userData.saveMin("keyName", 50); //save min value between current and provided
Countly.userData.setOnce("setOnce", 200);//insert value to array of unique values
Countly.userData.pushUniqueValue("type", "morning");//insert value to array of unique values
Countly.userData.pushValue("type", "morning");//insert value to array which can have duplicates
Countly.userData.pullValue("type", "morning");//remove value from arrayApplication Performance Monitoring
The Performance Monitoring feature allows you to analyze your application's performance on various aspects. For more details, please review the Performance Monitoring documentation.
The SDK provides manual and automatic mechanisms for Application Performance Monitoring (APM). All of the automatic mechanisms are disabled by default and to start using them you would first need to enable them and give the required consent if it was required:
const countlyConfig = new CountlyConfig("https://your.server.ly", "YOUR_APP_KEY");
// ...
// this interface exposes the available APM features and their modifications.
countlyConfig.apm.
Custom Traces
You may measure any operation you want and record it using custom traces. First, you need to start a trace by using the startTrace(traceKey) method:
Countly.startTrace(traceKey);
Then you may end it using the endTrace(traceKey, customMetric)method, optionally passing any metrics as key-value pairs:
String traceKey = "Trace Key";
Map<String, int> customMetric = {
"ABC": 1233,
"C44C": 1337
};
Countly.endTrace(traceKey, customMetric);The duration of the custom trace will be automatically calculated upon ending.
Trace names should be non-zero length valid strings, and custom metric values can only be numbers. Trying to start a custom trace with the already started name will have no effect. Trying to end a custom trace with already ended (or not yet started) name will have no effect.
You may also cancel any custom trace you started using the cancelTrace(traceKey)method:
Countly.cancelTrace(traceKey);
Additionally, if you need you may cancel all custom traces you started, using the clearAllTraces()method:
Countly.clearAllTraces(traceKey);
Network Traces
You may record manual network traces using the recordNetworkTrace(networkTraceKey, responseCode, requestPayloadSize, responsePayloadSize, startTime, endTime) method.
A network trace is a collection of measured information about a network request. When a network request is completed, a network trace can be recorded manually to be analyzed via Performance Monitoring later using the following parameters:
- networkTraceKey: A non-zero length valid string - responseCode: HTTP status code of the received response - requestPayloadSize: Size of the request's payload in bytes - responsePayloadSize: Size of the received response's payload in bytes - startTime: UNIX timestamp in milliseconds for the starting time of the request - endTime: UNIX timestamp in milliseconds for the ending time of the request
Countly.recordNetworkTrace(networkTraceKey, responseCode, requestPayloadSize, responsePayloadSize, startTime, endTime);
Automatic Device Traces
SDK can automatically track the app start time for you. Tracking of app start time is disabled by default and must be explicitly enabled by the developer during init.
For tracking app start time automatically you will need to enable it in SDK init config:
const countlyConfig = new CountlyConfig("https://your.server.ly", "YOUR_APP_KEY");
// enable it here separately with 'apm' interface.
countlyConfig.enableAppStartTimeTracking();This calculates and records the app launch time for performance monitoring.
If you want to determine when the end time for this calculation should be you will have to enable the usage of manual triggers together with enableAppStartTimeTracking during init:
const countlyConfig = new CountlyConfig("https://your.server.ly", "YOUR_APP_KEY");
// enable it here separately with 'apm' interface.
countlyConfig.apm.enableAppStartTimeTracking().enableManualAppLoadedTrigger();
Now you can call Countly.appLoadingFinished() any time after SDK initialization ( E.g. componentDidMount method) to record that moment as the end of app launch time. The starting time of the app load will be automatically calculated and recorded. Note that the app launch time can be recorded only once per app launch. So, the second and following calls to this method will be ignored.
If you also want to manipulate the app launch starting time instead of using the SDK calculated value then you will need to call a third method on the config object with the timestamp (in milliseconds) of that time you want:
const countlyConfig = new CountlyConfig("https://your.server.ly", "YOUR_APP_KEY");
// generate the timestamp you want (or you can directly pass a ts)
let ts = Date.now() - 500; // 500 ms before now
// this would also work with manual trigger
countlyConfig.apm.enableAppStartTimeTracking().setAppStartTimestampOverride(ts);
App Time in Background / Foreground
Lastly if you want to enable the SDK to record the time an app is in foreground or background automatically you would need to enable this option during init:
const countlyConfig = new CountlyConfig("https://your.server.ly", "YOUR_APP_KEY");
// enable it here separately with 'apm' interface.
countlyConfig.apm.enableForegroundBackgroundTracking();User Consent
Being compliant with GDPR and other data privacy regulations, Countly provides ways to toggle different Countly tracking features on or off depending on a user's given consent. For more details, please review the Compliance Hub plugin documentation.
Currently, available features with consent control are as follows:
- sessions - tracking when, how often, and how long users use your app
- events - allows sending events to the server
- views - allows tracking which views user visits
- location - allows sending location information
- crashes - allows tracking crashes, exceptions, and errors
- attribution - allows tracking from which campaign did the user come.
- users - allows collecting and providing user information, including custom properties.
- push - allows push notifications,
- metrics - allows sending separate metrics data
- star-rating - allows sending the results from Rating Feedback widgets.
- feedback - allows showing the results from Survey and NPS® Feedback widgets.
- apm - allows application performance monitoring.
- remote-config - allows downloading remote config values from your server.
Setup During Init
The requirement for consent is disabled by default. To enable it, you will have to call setRequiresConsent with true during initializing Countly.
const countlyConfig = new CountlyConfig("https://your.server.ly", "YOUR_APP_KEY");
// Enable consent requirement
countlyConfig.setRequiresConsent(true);By default, no consent is given. That means that if no consent is enabled, Countly will not work and no network requests related to its features will be sent.
To give consent during initialization, you have to call giveConsenton the config object with an array of consent values.
const countlyConfig = new CountlyConfig("https://your.server.ly", "YOUR_APP_KEY");The Countly SDK does not persistently store the status of given consents except push notifications. You are expected to handle receiving consent from end-users using proper UIs depending on your app's context. You are also expected to store them either locally or remotely. Following this step, you will need to call the giveConsent method on each app launch depending on the permissions you managed to get from the end-users.
Ideally you would give consent during initialization.
Changing Consent
The end-user can change their mind about consents at a later time.
To reflect these changes in the Countly SDK, you can use the removeConsent or giveConsent methods.
// To add/remove consent for a single feature (string parameter)
Countly.giveConsent("events");
Countly.removeConsent("events");
// To add/remove consent for a subset of features (array of strings parameters)
Countly.giveConsent(["events", "views", "star-rating", "crashes"]);
Countly.removeConsent(["events", "views", "star-rating", "crashes"]);You can also either give or remove consent to all possible SDK features:
// To add/remove consent for all available features Countly.giveAllConsent(); Countly.removeAllConsent();
Security and Privacy
Parameter Tampering Protection
You can set optional salt to be used for calculating checksum of request data, which will be sent with each request using &checksum field. You need to set exactly the same salt on the Countly server. If salt on Countly server is set, all requests would be checked for the validity of &checksum field before being processed.
const countlyConfig = new CountlyConfig("https://your.server.ly", "YOUR_APP_KEY");
// ...
countlyConfig.enableParameterTamperingProtection("salt"); // Enable tamper protection salt
await Countly.initWithConfig(countlyConfig); // Initialize the countly SDK with config.
Make sure not to use salt on the Countly server and not on the SDK side, otherwise, Countly won't accept any incoming requests.
Pinned Certificate (Call this method before initialization)
Terminal
openssl s_client -connect try.count.ly:443 -showcerts
Run the above command and copy the content inside the begin certificate and the end certificate.
Example files: Android and iOS. Note that Android needs the certificate string, while iOS needs the entire .cer file.
Android
cd AwesomeProject ls count.ly.cer mkdir -p ./android/app/src/main/assets/ cp ./count.ly.cer ./android/app/src/main/assets/
iOS
open ./ios/AwesomeProject.xcworkspace Right click on AwesomeProject and select `New Group` (ScreenShot 1). Name it `Resources`. Drag and Drop count.ly.cer file under that folder (ScreenShot 2). Make sure copy bundle resources has your certificate (Screenshot 4).
JavaScript
Countly.pinnedCertificates("count.ly.cer");Note that count.ly.cer is the name of the file. Replace this file with the one you have.
Using Proguard
The Android side of the SDK does not require specific proguard exclusions and can be fully obfuscated.
Other Features and Notes
SDK Config Parameters Explained
You may provide your own custom device ID when initializing the SDK using the method below.
// create Countly config object
const countlyConfig = new CountlyConfig("https://your.server.ly", "YOUR_APP_KEY");
// ...
countlyConfig.setDeviceId(DEVICE_ID); // Set device ID
await Countly.initWithConfig(countlyConfig); // Initialize the countly SDK with config.
Example Integrations
You can take a look at our example application in this GitHub repo. It shows how the majority of the SDK functionality can be used. After you have cloned the repo you can use the python script there to build the example.
SDK Internal Limits
Countly SDKs have internal limits to prevent users from unintentionally sending large amounts of data to the server. If these limits are exceeded, the data will be truncated to keep it within the limit. You can check the exact parameters these limits affect from here.
The SDK Internal Limit functions can be accessed via an interface called sdkInternalLimits, which is available through the CountlyConfig object, as demonstrated in the examples.
Key Length
Limits the maximum size of all user set keys (default: 128 chars):
CountlyConfig config = CountlyConfig(SERVER_URL, APP_KEY); config.sdkInternalLimits.setMaxKeyLength(int MAX_KEY_LENGTH); await Countly.initWithConfig(config);
Value Size
Limits the size of all user-set string segmentation (or their equivalent) values (default: 256 chars):
CountlyConfig config = CountlyConfig(SERVER_URL, APP_KEY); config.sdkInternalLimits.setMaxValueSize(int MAX_VALUE_SIZE); await Countly.initWithConfig(config);
Segmentation Values
Limits the amount of user-set segmentation key-value pairs (default: 100 entries):
CountlyConfig config = CountlyConfig(SERVER_URL, APP_KEY); config.sdkInternalLimits.setMaxSegmentationValues(int MAX_SEGMENTATION_COUNT); await Countly.initWithConfig(config);
Breadcrumb Count
Limits the amount of user-set breadcrumbs that can be recorded (default: 100 entries; exceeding this deletes the oldest one):
CountlyConfig config = CountlyConfig(SERVER_URL, APP_KEY); config.sdkInternalLimits.setMaxBreadcrumbCount(int MAX_BREADCRUMB_COUNT); await Countly.initWithConfig(config);
Stack Trace Lines Per Thread
Limits the stack trace lines that would be recorded per thread (default: 30 lines):
CountlyConfig config = CountlyConfig(SERVER_URL, APP_KEY); config.sdkInternalLimits.setMaxStackTraceLinesPerThread(int MAX_STACK_THREAD); await Countly.initWithConfig(config);
Stack Trace Line Length
Limits the characters that are allowed per stack trace line (default: 200 chars):
CountlyConfig config = CountlyConfig(SERVER_URL, APP_KEY); config.sdkInternalLimits.setMaxStackTraceLineLength(int MAX_STACK_LENGTH); await Countly.initWithConfig(config);
SDK Storage and Requests
For iOS: SDK data is stored in Application Support Directory in a file named "Countly.dat" For Android: SDK data is stored in SharedPreferences. A SharedPreferences object points to a file containing key-value pairs and provides simple methods to read and write them.
Setting Event Queue Threshold
Events get grouped together and are sent either every minute or after the unsent event count reaches a threshold. By default it is 10. If you would like to change this, call:
Countly.setEventSendThreshold(6);
Forcing HTTP POST
If the data sent to the server is short enough, the SDK will use HTTP GET requests. In the event you would like an override so that HTTP POST may be used in all cases, call the setHttpPostForced function before you have called initWithConfig:
// enabling the POST Countly.setHttpPostForced(true); // disabling the POST Countly.setHttpPostForced(false);
Interacting with the Internal Request Queue
When recording events or activities, the requests don't always get sent immediately. Events get grouped together. All the requests contain the same app key which is provided in the initWithConfig function.
There are two ways to interact with the app key in the request queue at the moment.
1. You can replace all requests with a different app key with the current app key:
//Replaces all requests with a different app key with the current app key. Countly.replaceAllAppKeysInQueueWithCurrentAppKey();
In the request queue, if there are any requests whose app key is different than the current app key, these requests app key will be replaced with the current app key. 2. You can remove all requests with a different app key in the request queue:
//Removes all requests with a different app key in request queue. Countly.removeDifferentAppKeysFromQueue();
In the request queue, if there are any requests whose app key is different than the current app key, these requests will be removed from the request queue.
Checking If the SDK Has Been Initialized
In the event you would like to check if initWithConfig has been called, use the function below.
Countly.isInitialized().then(result => console.log(result)); // true or false
Attribution
This feature is available for the Enterprise Edition.
There are 2 forms of attribution: direct Attribution and indirect Attribution.
Direct Attribution
You can pass "Campaign type" and "Campaign data". The "type" determines for what purpose the attribution data is provided. Depending on the type, the expected data will differ, but usually that will be a string representation of a JSON object.
You can use recordDirectAttribution to set attribution values during initialization.
const campaignData = 'JSON_STRING';
const config = CountlyConfig(SERVER_URL, APP_KEY);
config.recordDirectAttribution('CAMPAIGN_TYPE', campaignData);You can also use recordDirectAttribution function to manually report attribution later:
const campaignData = 'JSON_STRING';
Countly.recordDirectAttribution('CAMPAIGN_TYPE', campaignData);Currently this feature is limited and accepts data only in a specific format and for a single type. That type is "countly". It will be used to record install attribution. The data also needs to be formatted in a specific way. Either with the campaign id or with the campaign id and campaign user id.
const campaignData = '{cid:"[PROVIDED_CAMPAIGN_ID]", cuid:"[PROVIDED_CAMPAIGN_USER_ID]"}';
Countly.recordDirectAttribution('countly', campaignData);Indirect Attribution
This feature would be used to report things like advertising ID's. For each platform those would be different values. For the most popular keys we have a class with predefined values to use, it is called "AttributionKey".
You can use recordDirectAttribution to set attribution values during initialization.
const attributionValues = {};
if(Platform.OS.match('ios')){
attributionValues[AttributionKey.IDFA] = 'IDFA';
} else {
attributionValues[AttributionKey.AdvertisingID] = 'AdvertisingID';
}
const config = CountlyConfig(SERVER_URL, APP_KEY);
config.recordIndirectAttribution(attributionValues);You can also use recordIndirectAttribution function to manually report attribution later
const attributionValues = {};
if(Platform.OS.match('ios')){
attributionValues[AttributionKey.IDFA] = 'IDFA';
} else {
attributionValues[AttributionKey.AdvertisingID] = 'AdvertisingID';
}
Countly.recordIndirectAttribution(attributionValues);In case you would be accessing IDFA for ios, for iOS 14+ due to the changes made by Apple, regarding Application Tracking, you need to ask the user for permission to track the Application.
Custom Metrics
For overriding default metrics or adding extra ones that are sent with begin_session requests, you can use pass 'customMetric' Object to the function Countly.setCustomMetrics(customMetric), 'customMetric' should be an Object with keys and values that are both Strings only. Note that the custom metrics should be set before initialization.
var customMetric = {"key": "value"};
Countly.setCustomMetrics(customMetric);For more information on the specific metric keys used by Countly, check here.
Example to override 'Carrier' and 'App Version'
var customMetric = {"_carrier": "custom carrier", "_app_version": "2.1"};
Countly.setCustomMetrics(customMetric);Extended Device ID Management
Performance risk. Changing device id with server merging results in huge load on the server as it rewrites all the user history. This should be done only once per user.
You may configure or change the device ID anytime using the method below when you need explicit merge control.
Countly.deviceId.changeID(DEVICE_ID, MERGE);
You may either allow the device to be counted as a new device or merge it with the existing data on the server. If MERGE is set to true, the old device ID on the server will be replaced with the new one, and data associated with the old device ID will be merged automatically. Otherwise, if MERGE is set to false, the device will be counted as a new device on the server.
If you do not need to choose the merge behavior explicitly, use Countly.deviceId.setID(...) instead.
Extended Feedback Widget Options
When the widgets are created, you need to use 2 calls in your SDK to show them: one to get all available widgets for a user and another to display a chosen widget.
To get your available widget list, use the call below.
Countly.feedback.getAvailableFeedbackWidgets(function(retrivedWidgets, error){
if (error != null) {
console.log("Error : " + error);
}
else {
console.log(retrivedWidgets.length)
}
});From the callback, get the list of all available widgets that apply to the current device ID.
The objects in the returned list look like this:
{
"id": "WIDGET_ID",
"type": "WIDGET_TYPE",
"name": "WIDGET_NAME",
"tags": ["WIDGET_TAG"],
"widgetVersion": "WIDGET_VERSION"
}To determine what kind of widget that is, check the "type" value. The potential values are survey, nps and rating.
Then use the widget type and description (which is the same as provided in the Dashboard) to decide which widget to show.
Pass the retrieved widget object back unchanged when presenting it so metadata such as widgetVersion is preserved.
After you have decided which widget you want to display, call the function below.
Countly.feedback.presentFeedbackWidget(RETRIEVED_WIDGET_OBJECT, "CLOSE_BUTTON_TEXT", function() {
console.log("Widgetshown");
},
function() {
console.log("Widgetclosed");
})
Server Configuration
Server Configuration is enabled by default. Changes made on SDK Manager SDK Configuration on your server will affect SDK behavior directly.
In all cases, the configuration may not be applied during the app’s first run. If this is a security sensitive case for the situations, you can provide the server config to the SDK during initialization.
config.setSDKBehaviorSettings(configObject: object);
If you want to disable automatic config updates from the server, you can prevent the SDK from making server configuration fetch requests. This is useful if you're trying to reduce network traffic or control request counts.
countlyConfig.disableSDKBehaviorSettingsUpdates();
Backoff Mechanism
SDK would detect if a server is under load and hold off sending requests for a short time if there is no urgency to do so. If you want to disable this behavior you can use this config option:
countlyConfig.disableBackoffMechanism();
Request Timeout Duration
Each request the SDK makes has a 30 seconds default timeout duration. If you find it too restrictive or during testing you can change this value by:
countlyConfig.setRequestTimeoutDuration(seconds: number);
Custom Network Request Headers
You can add request headers either during initialization or later at runtime.
const countlyConfig = new CountlyConfig("https://your.server.ly", "YOUR_APP_KEY");
countlyConfig.addCustomNetworkRequestHeaders({
Authorization: "Bearer token",
"X-Client": "rn-app",
});
await Countly.initWithConfig(countlyConfig);
Countly.addCustomNetworkRequestHeaders({
"X-Trace-ID": "12345",
"X-Environment": "staging",
});Header values are stringified before they are sent. Entries with null or undefined values are ignored.
Android Request Queue Cleaner
On Android, the SDK gradually cleans old request data by default. If you need to disable that behavior during initialization, use:
countlyConfig.disableGradualRequestCleaner();
Recording Metrics
You can send device metrics with a separate call if needed. If you do not provide any override the SDK will collect this data internally:
Countly.recordMetrics(metricsOverride?: Record<string, string>): void;
You can check possible values you can override from here.