Setting up Countly SDK inside your Phonegap, Cordova, Icenium or Meteor application is straightforward. Just follow these steps.
Using SDK
First run the following to create a Countly demo application.
cordova create countly-demo-js com.countly.demo countly-demo-js
cd countly-demo-js
Add Countly core plugin
cordova plugin add https://github.com/Countly/countly-sdk-cordova.git
# OR
cordova plugin add countly-sdk-js@19.9.3
Now add platform of your choice
cordova platform add android
cordova platform add ios
It's important that you make sure you build it with Cordova, as Cordova links folders very well.
cordova build android
cordova build ios
Now run the application directly for Android,
cordova run android
Or iOS:
cordova run ios
Alternatively, you can open the source in Xcode, or Eclipse and move on with further development.
Using SDK with Meteor app
Run this command for Meteor:
meteor add countly:countly-sdk-js
Ionic 2.0
npm install -g ionic cordova
ionic start countly-demo-ionic blank
cd countly-demo-ionic
ionic cordova plugin add https://github.com/Countly/countly-sdk-cordova.git
ionic serve
# Note to ionic devs: This plugin does not work on a browser.
In your index.html, use the following lines:
<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src="Countly.js"></script>
If you looking to try out example code, you may wanna look at the index.html in the countly-sdk-cordova repo in master branch.
Copy and paste into your www/index.html
It has all the required examples you need.
Implementation
Below you can find necessary code snippets to initialize the SDK for sending data to Countly servers. Where possible, use your server URL instead of try.count.ly
in case you have your own server.
// initialize
// use your server name below if required.
Countly.init("https://try.count.ly","App_Key");
//example to start and stop Countly
Countly.start();
Countly.stop();
//example to halt Countly
Countly.halt();
Enabling logging
If logging is enabled then our sdk will print out debug messages about it's internal state and encountered problems.
When advise doing this while implementing countly features in your application.
// example for setLoggingEnabled
Countly.setLoggingEnabled();
Forcing HTTP POST
If the data sent to the server is short enough, the sdk will use HTTP GET requests. In case you want an override so that HTTP POST is used in all cases, call the "setHttpPostForced" function after you called "init". You can use the same function to later in the apps life cycle disable the override. This function has to be called every time the app starts.
Countly.setHttpPostForced(true); // default is false
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 Countly server. If salt on Countly server is set, all requests would be checked for validity of &checksum field before being processed.
// sending data with salt
Countly.enableParameterTamperingProtection("salt");
Setting up custom events
A custom event is any type of action that you can send to a Countly instance, e.g purchase, settings changed, view enabled and so. This way it's possible to get much more information from your application compared to what is sent from Android SDK to Countly instance by default.
Data passed should be in UTF-8
All data passed to Countly server via SDK or API should be in UTF-8.
As an example, we will be recording a purchase event. Here is a quick summary what information each usage will provide us:
- 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 + the total duration of those events.
1. Event key and count
// example for sending basic custom event
var events = {"key":"Basic Event","count":1};
Countly.recordEvent(events);
2. Event key, count and sum
// example for event with sum
var events = {"key":"Event With Sum","count":1,"sum":"0.99"};
Countly.recordEvent(events);
3. Event key and count with segmentation(s)
// example for event with segment
var events = {"key":"Event With Segment","count":1};
events.segments = {"Country" : "Turkey", "Age" : "28"};
Countly.recordEvent(events);
4. Event key, count and sum with segmentation(s)
// example for event with segment and sum
var events = {"key":"Event With Segment And Sum","count":1,"sum":"0.99"};
events.segments = {"Country" : "Turkey", "Age" : "28"};
Countly.recordEvent(events);
5. Event key, count, sum and duration with segmentation(s)
var events = {
"key": "Event With Sum And Segment duration",
"count": 1,
"Sum": "0.99",
"duration": "0"
};
events.segments = {
"Country": "Turkey",
"Age": "28"
};
Countly.recordEvent(events);
Those are only a few examples with what you can do with custom events. You can extend those examples and use country, app_version, game_level, time_of_day and any other segmentation that will provide you valuable insights.
Timed events
It's possible to create to create timed events by defining a start and stop moment.
// Time Event
Countly.startEvent("Timed Event");
setTimeout(function() {
Countly.endEvent({ "key": "Timed Event");
}, 1000);
// Time Event With Sum
Countly.startEvent("Timed Event With Sum");
setTimeout(function() {
countly.endEvent({"key": "Timed Event With Sum", "sum": "0.99"});
}, 1000);
When ending a event you can also provide additional information. But in that case you have to provide segmentation, count and sum. The default values for those are "null", 1 and 0.
// Time Event with segment
Countly.startEvent("Timed Event With Segment");
setTimeout(function() {
var events = {
"key": "Timed Event With Segment"
};
events.segments = {
"Country": "Turkey",
"Age": "28"
};
Countly.endEvent(events);
}, 1000)
// Time Event with Segment, sum and count
Countly.startEvent("Timed Event With Segment, Sum And Count");
setTimeout(function() {
var events = {
"key": "timedEvent",
"count": 1,
"sum": "0.99"
};
events.segments = {
"Country": "Turkey",
"Age": "28"
};
Countly.endEvent(events);
}, 1000);
Device ID
When the SDK is initialized for the first time and no device ID is provided, a device ID will be generated by SDK.
For iOS: the device ID generated by SDK is the Identifier For Vendor (IDFV)
For Android: the device ID generated by SDK is the OpenUDID or Google Advertising ID
You may provide your own custom device ID when initializing the SDK
Countly.init(SERVER_URL, APP_KEY, DEVICE_ID)
Changing the Device ID
You may configure/change the device ID anytime using:
Countly.changeDeviceId(DEVICE_ID, ON_SERVER);
You may either allow the device to be counted as a new device or merge existing data on the server. If theonServer
bool 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 onServer
bool is set to false
, the device will be counted as a new device on the server.
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.
You can enable temporary device ID when initializing the SDK:
Countly.init(SERVER_URL, APP_KEY, "TemporaryDeviceID")
To enable a temporary device ID after init, you would call:
Countly.changeDeviceId(Countly."TemporaryDeviceID", ON_SERVER);
Note: When passing TemporaryDeviceID
for deviceID
parameter, argument for onServer
parameter does not matter.
As long as the device ID value is TemporaryDeviceID
, 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.changeDeviceId(DEVICE_ID, ON_SERVER);
method, all requests which have been kept on hold until that point will start with the real device ID
Retrieving the device id and its type
You may wanty to see what device id Countly is assigning for the specific device and what the source of that id is. For that you may use the following calls. The id type is an enum with the possible values of: "DEVELOPER_SUPPLIED", "OPEN_UDID", "ADVERTISING_ID".
// get device id
Countly.getDeviceID(function(deviceId){
console.log(deviceId);
}, function(getDeviceIDError){
console.log(getDeviceIDError);
});
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 apps user base or to send them tailored push notifications based on their coordinates. There are 4 fields that can be provided:
- country code in the 2 letter iso standard
- city name (has to be set together with country code)
- Comma separate latitude and longitude values, for example "56.42345,123.45325"
- ip address of your user
// send user location
Countly.setLocation("28.006324", "-82.7166183");
When those values are set, they will be sent every time when initiating a session. If they are set after a session was initiated, a separate request will also be sent. Except for ip address, because Countly Server processes ip address only when starting a session.
If you don't want to set specific fields, set them to null.
Users might want to opt out of location tracking. To do that, call:
It will erase cached location data from the device and the server.
Remote Config
Remote config allows you to modiffy how your app functions or looks by requesting key-value pairs from your Countly server. The returned values can be modiffied based on the user profile. For more details please see Remote Config documentation.
Automatic Remote Config download
There are two ways of acquiring remote config data, by automatic download or manual request. By default, automatic remote config is disabled and therefore without developer intervention no remote config values will be requested.
Automatic value download happens when the SDK is initiated or when the device ID is changed. To enable it, you have to call setRemoteConfigAutomaticDownload before init. As a optional value you can provide a callback to be informed when the request is finished.
Note: call setRemoteConfigAutomaticDownload
method before init
// Call this method before init
Countly.setRemoteConfigAutomaticDownload(function(r){
alert(r)
}, function(r){
alert(r);
});
If the callback returns a non null value, then you can expect that the request failed and no values where updated.
When doing an automatic update, all locally stored values are replaced with the ones received (all locally stored ones are deleted and new ones are associated instead). It is possible that a previously valid key returns no value after an update.
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
Each of these requests also has a callback. If that returns a non-null value, that means the request encountered an error and failed.
Functionally, the manual update for everything remoteConfigUpdate is the same as the automatic update - it replaces all stored values with the ones from the server (all locally stored ones are deleted and replaced with new ones instead). The advantage is that you can make the request whenever it is desirable for you. It has a callback to let you know when it has finished.
Countly.remoteConfigUpdate(function(r){
alert(r)
}, function(r){
alert(r);
});
You might want to update only specific key values. For that you need to call updateRemoteConfigForKeysOnly
with a list of keys you want to be updated. That list is an array with string values of those keys. It has a callback to let you know when the request has finished.
Countly.updateRemoteConfigForKeysOnly(["name"], function(r){
alert(r)
}, function(r){
alert(r);
});
You might want to update all values except a few defined keys, for that call updateRemoteConfigExceptKeys. The key list is a array with string values of the keys. It has a callback to let you know when the request has finished.
Countly.updateRemoteConfigExceptKeys(["url"], function(r){
alert(r)
}, function(r){
alert(r);
});
When making requests with a "inclusion" or "exclusion" array, if those arrays ar empty or null, they will function the same as a simple manual request and will update all values. This means that it will also erase all keys not returned by the server.
Getting Remote Config values
To request a stored value, call getRemoteConfigValueForKey
with the specified key. If it returns null then no value was found. The SDK has no knowledge of the returned value type and therefore returns an object. The developer needs to cast it to the appropriate type. The returned values can also be a JSONArray, JSONObject or just a simple value like int.
Countly.getRemoteConfigValueForKey("name", function(r){
alert(r)
}, function(r){
alert(r);
});
Clearing stored Remote Config values
At some point you might want to erase all values downloaded from the server. To achieve that you need to call one function, depicted below:
Countly.remoteConfigClearValues(function(r){
alert(r)
}, function(r){
alert(r);
});
Setting up User Profiles
Available with Enterprise Edition, User Profiles is a tool which helps you identify users, their devices, event timeline and application crash information. User Profiles can contain any information that either you collect, or is collected automatically by Countly SDK.
You can send user related information to Countly and let Countly dashboard show and segment this data. You may also send a notification to a group of users. For more information about User Profiles, see this documentation.
To provide information about the current user, you must call the Countly.userData.setUserData function. You can call it by providing a bundle of only the predefined fields or call it while also providing a second bundle of fields with your custom keys. After you have provided user profile information, you must save it by calling Countly.userData.save().
/ example for setting user data
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 = "Male";
options.byear = 1919;
Countly.setUserData(options);
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 organisation name |
phone | String | User's phone number |
picture | String | URL to avatar or profile picture of the user |
gender | String | User's gender as M for male and F for female |
byear | String | User's year of birth as integer |
Using "" for strings or a negative number for 'byear' will effectively delete that property.
For custom user properties you may use any key values to be stored and displayed on your Countly backend. Note: keys with . or $ symbols will have those symbols removed.
Modifying custom data
Additionally you can do different manipulations on your custom data values, like increment current value on server or store a array of values under the same property.
Below is the list of available methods:
// example for extra user features
Countly.userData.setProperty("setProperty", "My Property");
Countly.userData.increment("increment");
Countly.userData.incrementBy("incrementBy", 10);
Countly.userData.multiply("multiply", 20);
Countly.userData.saveMax("saveMax", 100);
Countly.userData.saveMin("saveMin", 50);
Countly.userData.setOnce("setOnce", 200);
Countly.userData.pushUniqueValue("pushUniqueValue","morning");
Countly.userData.pushValue("pushValue", "morning");
Countly.userData.pullValue("pullValue", "morning");
In the end always call Countly.userData.save() to send them to the server.
User Consent management
To be compliant with GDPR, starting from 18.04, Countly provides ways to toggle different Countly features on/off depending on the given consent.
More information about GDPR can be found here.
By default the requirement for consent is disabled. To enable it, you have to call setRequiresConsent with true, before initializing Countly.
Countly.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 features, will be sent. When consent status of a feature is changed, that change will be sent to the Countly server.
For all features, except push, consent is not persistent and will have to be set every time before countly init. Therefore the storage and persistance of given consent falls on the sdk integrator.
Consent for features can be given and revoked at any time, but if it is given after Countly init, some features might work partially.
If consent is removed, but the appropriate function can't be called before the app closes, it should be done at next app start so that any relevant server side features could be disabled (like reverse geo ip for location)
Feature names in the Android SDK are stored as static fields in the class called CountlyFeatureNames.
The current features are:
- sessions - tracking when, how often and how long users use your app
- events - allow sending custom events to server
- views - allow tracking which views user visits
- location - allow sending location information
- crashes - allow tracking crashes, exceptions and errors
- attribution - allow tracking from which campaign did user come
- users - allow collecting/providing user information, including custom properties
- push - allow push notifications
- starRating - allow to send their rating and feedback
- apm - allow application performance monitoring
Changing consent
There are 3 ways of changing feature consent:
- giveConsent/removeConsent - gives or removes consent to a specific feature
//giveConsent
Countly.giveConsent(["events", "views", "star-rating", "crashes"]);
// removeConsent
Countly.removeConsent(["events", "views", "star-rating", "crashes"]);
- giveAllConsent/removeAllConsent - giveAll or removeAll consent to a specific feature
//giveAllConsent
Countly.giveAllConsent();
//removeAllConsent
Countly.removeAllConsent();
Crash reporting
With this feature, Countly SDK will generate a crash report if your application crashes due to an exception, and send it to Countly server for further inspection.
If a crash report can not be delivered to server (e.g. no internet connection, unavailable server), then SDK stores the crash report locally in order to try again later.
Please add to your html file:
// Using countly crash reports
Countly.enableCrashReporting();
You can also send a custom crash log to Countly using code below.
// Send a custom crash log
Countly.addCrashLog("My crash log from JavaScript");
// Send Exception to the server
Countly.logException(["My Customized error message"], true, {"_facebook_version": "0.0.1"});
Countly.logException(stackFramesFromStackTraceJS, booleanNonFatal, segments);
// Usage Example
app.addCrashLog = function(){
Countly.addCrashLog("User Performed Step A");
setTimeout(function(){
Countly.addCrashLog("User Performed Step B");
},1000);
setTimeout(function(){
Countly.addCrashLog("User Performed Step C");
console.log("Opps found and error");
Countly.logException("My Customized error message");
},1000);
}
View tracking
You can manually add your own views in your application, and each view will be visible under Analytics > Views. Below you can see two examples of sending a view using Countly.recordview
function.
// record a view on your application
Countly.recordView("My Home Page");
Countly.recordView("Profile Page");
Application Performance Monitoring
Minimum Countly SDK Version
This feature is only supported by the minimum SDK version 20.4.0.
Performance Monitoring feature allows you to analyze your application's performance on various aspects. For more details please see Performance Monitoring documentation.
Here is how you can utilize Performance Monitoring feature in your apps:
First, you need to enable Performance Monitoring feature::
Countly.enableApm(); // Enable APM features.
With this, Countly SDK will start measuring some performance traces automatically. Those include app foreground time, app background time. Additionally, custom traces and network traces can be manually recorded.
Custom trace
You may also 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 on ending. Trace names should be non-zero length valid strings. 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 cancelTrace(traceKey)
method:
Countly.cancelTrace(traceKey);
Additionally, if you need you may cancel all custom traces you started, using clearAllTraces()
method:
Countly.clearAllTraces(traceKey);
Network trace
You may record manual network traces using therecordNetworkTrace(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 in the Performance Monitoring feature later with 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 time stamp in milliseconds for the starting time of the request
- endTime
: UNIX time stamp in milliseconds for the ending time of the request
Countly.recordNetworkTrace(networkTraceKey, responseCode, requestPayloadSize, responsePayloadSize, startTime, endTime);
Getting user feedback
There are two ways of getting feedback from your users: Star rating dialog, feedback widget.
Star rating dialog allows users to give feedback as a rating from 1 to 5. The feedback widget allows to get the same 1 to 5 rating and also a text comment.
Feedback widget
Feedback widget shows a server configured widget to your user devices.
It's possible to configure any of the shown text fields and replace with a custom string of your choice.
In addition to a 1 to 5 rating, it is possible for users to leave a text comment and also leave a email in case the user would want some contact from the app developer.
Trying to show the rating widget is a single call, but underneath is a two step process. Before it is shown, the SDK tries to contact the server to get more information about the dialog. Therefore a network connection to it is needed.
You can try to show the widget after you have initialized the SDK. To do that, you first have to get the widget ID from your server:
Using that you can call the function to show the widget popup:
// Feedback Modal
countly.askForFeedback("5e425407975d006a22535fc", "close");
Star rating dialog
Star rating integration provides a dialog for getting user's feedback about the application. It contains a title, simple message explaining what it is for, a 1-to-5 star meter for getting users rating 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 just for getting a brief feedback from users, to be displayed on the Countly dashboard. If the user dismisses star rating dialog without giving a rating, the event will not be recorded.
Star-rating dialog's title, message and dismiss button text can be customized either through the init function or the SetStarRatingDialogTexts
function. If you don't want to override one of those values, set it to "null".
// Star Rating
countly.askForStarRating(Function(ratingResult){
console.log(ratingResult);
});
Push notifications
Countly uses PhoneGap push notifications plugin. Here is the link to its installation instructions. First, please follow the installation guidelines for installing it in Android and iOS.
Here are the steps to make push notifications work:
- Go to https://firebase.google.com
- Register / Login to the Firebase console. You should be logged in to https://console.firebase.google.com.
- Create and select a project if you haven't done before.
- Go to Settings > Project settings.
- Create an app for Android and iOS.
- Download the
google-services.json
for Android andGoogleService-Info.plist
for iOS. - Place both files under your root project folder. i.e. above www folder.
- Put these tags in config.xml file for Android and iOS:
<platform name="android"> <resource-file src="google-services.json" target="app/google-services.json" /> </platform>
<platform name="ios"> <resource-file src="GoogleService-Info.plist" /> </platform>
- Install the push notifications plugin.
cordova plugin add phonegap-plugin-push
- Build your app, and test push notifications.
Limitations of Cordova
Due to limitations of the way push is handled in a Cordova application, it's not possible to report back actions done when a push notification is received.
Push Method Implementation
First, when setting up push for the Cordova SDK, you would first select the push token mode. This would allow you to choose either test or production modes, push token mode should be set before init.
// Important call this method before init method
Countly.pushTokenType(Countly.messagingMode.DEVELOPMENT, "Channel Name", "Channel Description");
// Countly.messagingMode.DEVELOPMENT
// Countly.messagingMode.PRODUCTION
// Countly.messagingMode.ADHOC
When you are finally ready to initialize Countly push, you would call Countly.askForNotificationPermission(), this function should be call after init.
// Call this method any time.
Countly.askForNotificationPermission();
// This method will ask for permission,
// and send push token to countly server.
Cordova code to receive notification data. Call anywhere or event before init.
Countly.registerForNotification(function(theNotification){
console.log(JSON.stringify(theNotification));
});
Rich Push Notification
For Android, there is no special procedure required, you can install the community plugin, and it should work.
For iOS, you will need to follow these instruction: https://resources.count.ly/docs/countly-sdk-for-ios-and-os-x#section-rich-push-notifications-ios10-only-
Removing Plugin
cordova plugin remove countly-sdk-js
cordova platform remove android
cordova platform remove ios
Troubleshooting
If you get the following error during implementation (for versions before v1.0 SDK):
NSPersistentStoreCoordinator with a nil model
In this case, go to https://github.com/Countly/countly-sdk-cordova/tree/master/src/ios/sdk. Drag and drop "Countly.xcdatamodeld" folder into your plugins folder, and then build it using Xcode.
Warning about Java
Note: As per the new release v1.0 you will need Java 1.8 to bundle the application. You will need to update the CLASSPATH environment variable of Java and Javac to Java version 1.8
If you would like to set logging, use code snippet below in your code.
// example for setLoggingEnabled
//Countly.setLoggingEnabled();
Optional parameters during initialization You can provide optional parameters that will be used during begin_session request. They must be set right after the init
function so that they are set before the request is sent to the server. To set them, use the setOptionalParametersForInitialization
function. If you want to set those optional parameters, this function has to be called every time the app starts. If you don't to set one off those values, leave that field null
.
The optional parameters are:
- Country code: ISO Country code for the user's country
- City: Name of the user's city
- Location: Comma separate latitude and longitude values, for example "56.42345,123.45325"
//setting optional parameters
Countly.setOptionalParametersForInitialization({
city: "Tampa",
country: "US",
latitude: "28.006324",
longitude: "-82.7166183",
ipAddress: "255.255.255.255"
});
//and then call the below code
Countly.init(this, "https://YOUR_SERVER", "YOUR_APP_KEY", "YOUR_DEVICE_ID")