Countly Documentation

Countly Resources

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

Web Analytics (JavaScript)

This documentation shows how to install Countly JS tracker and use Countly to track your web page in detail.

In order to track your web server pages, you need Countly Javascript tracking library. This library comes ready & automatically hosted on your Countly server (at http://yourdomain.com/sdk/web/countly.min.js) and can be updated via command line. This library also works well with mobile applications that consist of HTML5 views.

Optionally, you can also use package managers to get the library (but you don't have to, as it comes ready):

npm install countly-sdk-web
bower install countly-sdk-web
yarn add countly-sdk-web

Before starting, for those who have examined our mobile SDKs - we can tell that custom events or tags that are used in mobile SDKs are quite similar to those we use in Javascript code. For example, it's possible to modify custom property values of user details, with modification commands like inc, mul, max, or min. Likewise, any custom events can be sent with segmentation easily.

What is an APP KEY?

You'll see APP_KEY definition above. This key is generated automatically when you create a website for tracking on Countly dashboard. Note that APP KEY is different from API KEY, which is used to send data via API calls.

To retrieve your APP_KEY, go to Management -> Applications and select your app, and you will see App Key field

Setting up (Recommended asynchronous usage)

You can use Countly Web SDK asynchronously, without blocking content loading, and use it even if Countly script is not loaded yet, by pushing function calls into Countly.q queue or synchronously allowing for script to load, before executing any functions.

It's suggested to insert asynchronous code, before the closing </head> tag. While Synchronous code should be added towards the bottom of the page, before closing </body> tag.

Example setup would look like this:

<script type='text/javascript'>
  
//some default pre init
var Countly = Countly || {};
Countly.q = Countly.q || [];

//provide your app key that you retrieved from Countly dashboard
Countly.app_key = "YOUR_APP_KEY";

//provide your server IP or name. Use try.count.ly for EE trial server.
//if you use your own server, make sure you have https enabled if you use
//https below.
Countly.url = "https://yourdomain.com"; 

//start pushing function calls to queue
//track sessions automatically
Countly.q.push(['track_sessions']);
  
//track sessions automatically
Countly.q.push(['track_pageview']);
  
//load countly script asynchronously
(function() {
	var cly = document.createElement('script'); cly.type = 'text/javascript'; 
	cly.async = true;
	//enter url of script here
	cly.src = 'https://cdn.jsdelivr.net/countly-sdk-web/latest/countly.min.js';
	cly.onload = function(){Countly.init()};
	var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(cly, s);
})();
</script>
<!--Countly script-->
<script type='text/javascript' src='https://cdn.jsdelivr.net/countly-sdk-web/latest/countly.min.js'></script>
<script type='text/javascript'>

Countly.init({
//provide your app key that you retrieved from Countly dashboard
  	app_key: "YOUR_APP_KEY",

//provide your server IP or name. Use try.count.ly for EE trial server.
//if you use your own server, make sure you have https enabled if you use
//https below.
    url: "http://yourdomain.com" 
    
	});
	//track sessions automatically
	Countly.track_sessions();
	//track pageviews automatically
	Countly.track_pageview();
</script>

In example above, we used Cloudflare CDN to retrieve Countly JS SDK. There are two options here, using Cloudflare or JSDeliver, and both of them are highly available CDNs.

As an alternative, you can also use /sdk/web/countly.min.js to get this SDK directly from your Countly server.

As the third alternative option, you can download countly.min.js from our Github repository and upload it to any server where you want to host it. You only would need to point this minified JS tracker lib in your small code above.

And then you can make custom event calls like:

<script type='text/javascript'>
//send event on button click
function clickEvent(ob){
	Countly.q.push(['add_event',{
		key:"asyncButtonClick", 
		segmentation: {
			"id": ob.id
		}
	}]);
}
</script>
<input type="button" id="asyncTestButton" onclick="clickEvent(this)" value="Test Button">
<script type='text/javascript'>
  //send event on button click
  function clickEvent(ob){
    Countly.add_event({
      key:"buttonClick", 
      segmentation: {
        "id": ob.id
      }
    });
  }
</script>
<input type="button" id="testButton" onclick="clickEvent(this)" value="Test Button">

Why can’t I see AngularJS errors on Countly dashboard?

AngularJs swallows errors by default. You need to extend angular's $exceptionHandler to call Countly.log_error() . For more information, see this blog post.

Generate custom SDK code snippets

Countly Code Generator can be used to generate custom SDK code snippets easily and fast. You can provide values for your custom event, or user profile, or just start with basic integration and this service will generate necessary code for you to use in your favorite IDE.

Setup properties

Here are the properties you can setup on Countly initialization

  • app_key - mandatory, app key for your app created in Countly
  • device_id - to identify a visitor, will be auto generated if not provided
  • url - your Countly server url - you can also use your own server URL or IP here
  • app_version - (optional) the version of your app or website
  • country_code - (optional) country code for your visitor
  • city - (optional) name of the city of your visitor
  • ip_address - (optional) ip address of your visitor
  • debug - output debug info into console (default: false)
  • ignore_bots - option to ignore traffic from bots (default: true)
  • interval - set an interval how often to check if there is any data to report and report it (default: 500 ms)
  • fail_timeout - set time in seconds to wait after failed connection to server (default: 60 seconds)

Setting up properties in Countly Web SDK is as follows (use your own server name if not using try.count.ly below):

Countly.debug = false;
Countly.app_key = "YOUR_APP_KEY";
Countly.device_id = "1234-1234-1234-1234";
Countly.url = "https://try.count.ly";
Countly.app_version = "1.2";
Countly.country_code = "LV";
Countly.city = "Riga";
Countly.ip_address = "83.140.15.1";
Countly.init({
			debug:false,
			app_key:"YOUR_APP_KEY",
			device_id:"1234-1234-1234-1234",
			url: "https://cloud.count.ly",
			app_version: "1.2",
			country_code: "LV",
			city: "Riga",
			ip_address: "83.140.15.1"
		}
});

Helper methods

Helper methods created to allow you easily track most common actions on the web.

Choose your helper methods carefully

Helper methods we provide below are both for synchronous and asynchronous tracking code. Choose the right helper method depending on your implementation.

Track Sessions

This method will automatically track user sessions, by calling begin extend and end session methods

Countly.q.push(['track_sessions']);
Countly.track_sessions();

Track Pageviews

This method will track current pageview, by using location.path as page name and report it to server

Countly.q.push(['track_pageview']);
Countly.track_pageview();

For Ajax updated contents and single page web applications, pass page name as a parameter to record new page view

Countly.q.push(['track_pageview','pagename']);
Countly.track_pageview("pagename");

Track Clicks (Enterprise edition)

This method will automatically track clicks on last reported view and display them on the heat map

Countly.q.push(['track_clicks']);
Countly.track_clicks();

Track Link clicks

This method will track click to specific links and will report with custom events with key linkClick and link's text, id and url as segments.

By default all links would be tracked for whole page, but you may provide the parent node as a parameter for which to track link clicks

Countly.q.push(['track_links']);
Countly.track_links();

Track Form Submissions

This method will automatically track form submissions and collect form data and input values in the form and report as Custom Event with formSubmit key

By default all forms would be tracked for whole page, but you may provide the parent node as a parameter for which to track forms.

Countly.q.push(['track_forms']);
Countly.track_forms();

Report conversion

When using Countly attribution analytics, you can also report conversion to Countly server, like for example when visitor purchased something or registered.

By default if user came to your website through Countly campaign link, campaign information will be automatically stored for this users and used when reporting conversion. If conversion is not reported yet, then when visiting through other campaign link, campaign information will be overwritten, so when you report the conversion, it would report the latest campaign user used to access your website.

But you can also overwrite that data and provide some specific campaign id for which you want to report conversion.

If there is no stored campaign data and you don't provide any campaign id, then conversion will not be reported.

Note: that conversion for each user may be reported only once, all other conversions will be ignored for this same user

//user stored conversion data
Countly.q.push(['report_conversion']);

//or provide campaign id yourself
Countly.q.push(['report_conversion', "MyCampaignID"]);
//user stored conversion data
Countly.report_conversion();

//or provide campaign id yourself
Countly.report_conversion("MyCampaignID");

Automatically fill user data

In most cases you don't know anything about your users, but would like to try to collect any data you can. For that purpose we provide 2 helper methods

Collect user data from filled forms

This method will look into forms filled by your users and will try to gather data like name, email address, username, etc from that data.
By default all forms will be checked, but optionally you can provide form element if you want to collect data only from specific form, or call method multiple times for different forms.
Also if you already provide data for users, you would not want to over write it, so you can provide third parameter as true to indicate that found data should be stored in custom properties

//collect data from forms
Countly.q.push(['collect_from_forms']);

//collect data from specific form
Countly.q.push(['collect_from_forms', formElement]);

//collect from forms and report as custom user properties
Countly.q.push(['collect_from_forms', document, true]);
//collect data from forms
Countly.collect_from_forms();

//collect data from specific form
Countly.collect_from_forms(formElement);

//collect from forms and report as custom user properties
Countly.collect_from_forms(document, true);

Password and other sensitive data will be omitted, but if you explicitly won't to exclude some form input from being processed, just add css class cly_user_ignore to that element.
Or on the contrary you can specify to collect data from this input as provided key, by adding prefixed css class clyuser{key} so if you want to store data as name, you should specify cly_user_name css class.

<form method='post' name='test_form'>
  <!-- data will be checked in this input -->
<p><input type="text" name="e" value="myemail@mydomain.com"></p>
  
<!-- ignore this input -->
<p><input type="text" name="e" value="notmyemail@notmydomain.com" class="cly_user_ignore"></p>

<!-- get customfield by class -->
<p><input type="text" name="custom" id="custom" value="value" class="cly_user_key1"></p>
  
<p><input id="submit-form" type="submit" value="Submit"></p>
  
</form>

Collect user data from Facebook

If your website uses Facebook Javascript SDK, you can use this helper method to automatically collect user data from their Facebook account. Just call the method right after Facebook SDK initialization and optionally provide object with custom properties and graph paths for values where to get them.

Here is an example how to get data from Facebook and also include location and timezone as custom properties.

<script src="https://connect.facebook.net/en_US/all.js"></script>
<script type="text/javascript">
FB.init({
    appId: '251676171676751',
    status: true,
    cookie: true,
    oauth: true
});

function CountlyGatherFBData(){
    Countly.collect_from_facebook({"location":"location.name", "tz":"timezone"});
};

FB.getLoginStatus(function(stsResp) {
    if(stsResp.authResponse) {
        CountlyGatherFBData();
    } else {
        FB.login(function(loginResp) {
            if(loginResp.authResponse) {
                CountlyGatherFBData();
            } else {
                alert('Please authorize this application to use it!');
            }
        });
    }
});
</script>

Custom Events

Adding an event

Custom event is a way to track any custom actions or other data you want to track from your website. You can also provide segments to be able to view breakdown of action by provided segment values.

Custom event consists of Javascript object with keys:

  • key - the name of the event (mandatory)
  • count - number of events (default: 1)
  • sum - sum to report with event (optional)
  • dur - duration to report with event (optional)
  • segmentation - an object with key/value pairs to report with event as segments

Here is an example of adding a custom event with all possible properties:

Countly.q.push(['add_event',{
	"key": "click",
  "count": 1,
  "sum": 1.5,
  "dur": 30,
	"segmentation": {
    "key1": "value1",
    "key2": "value2"
	}
}]);
Countly.add_event({
	"key": "click",
  "count": 1,
  "sum": 1.5,
  "dur": 30,
	"segmentation": {
    "key1": "value1",
    "key2": "value2"
	}
});

Timed Events

You can report time or duration with every event by providing dur property of the events object. But if you want, you can also let Web SDK to track duration of some specific event for you, you can use start_event and end_event methods.

Firstly you can start tracking event time by providing name of the event (which later on will be used as key for event object)

Countly.q.push(['start_event', 'timedEvent']);
Countly.start_event("timedEvent")

Countly will internally mark the start of event and will wait until you end event with end_event method, setting up dur property based on how much time has passed since start_event for same event name was called.

//end event
Countly.q.push(['end_event', 'timedEvent']);

//or end event with additional data
Countly.q.push(['end_event',{
	"key": "timedEvent",
  "count": 1,
  "sum": 1.5,
	"segmentation": {
    "key1": "value1",
    "key2": "value2"
	}
}]);
//end event
Countly.end_event("timedEvent")

//or end event with additional data
Countly.end_event({
	"key": "timedEvent",
  "count": 1,
  "sum": 1.5,
	"segmentation": {
    "key1": "value1",
    "key2": "value2"
	}
});

User Profiles and Custom data

User details

If you have any details about the user/visitor, you can provide Countly with that information. This will allow you track each and specific user on "User Profiles" tab, which is available with Countly Enterprise Edition.

The list of possible parameters you can pass is:

Countly.q.push(['user_details',{
    "name": "Arturs Sosins",
    "username": "ar2rsawseen",
    "email": "test@test.com",
    "organization": "Countly",
    "phone": "+37112345678",
    //Web URL to picture
    "picture": "https://pbs.twimg.com/profile_images/1442562237/012_n_400x400.jpg", 
    "gender": "M",
    "byear": 1987, //birth year
    "custom":{
      "key1":"value1",
      "key2":"value2",
      ...
    }
}]);
Countly.user_details({
    "name": "Arturs Sosins",
    "username": "ar2rsawseen",
    "email": "test@test.com",
    "organization": "Countly",
    "phone": "+37112345678",
    //Web URL pointing to user picture
    "picture": "https://pbs.twimg.com/profile_images/1442562237/012_n_400x400.jpg", 
    "gender": "M",
    "byear": 1987, //birth year
    "custom":{
      "key1":"value1",
      "key2":"value2",
      ...
    }
 });

Modifying custom data

Additionally you can do different manipulations on custom data values, like increment current value on server or store array of values under same property.

Below is the list of available methods:

Countly.q.push(['userData.set', key, value]) //set custom property
Countly.q.push(['userData.set_once', key, value]) //set custom property only if property does not exist
Countly.q.push(['userData.increment', key]) //increment value in key by one
Countly.q.push(['userData.increment_by', key, value]) //increment value in key by provided value
Countly.q.push(['userData.multiply', key, value]) //multiply value in key by provided value
Countly.q.push(['userData.max', key, value]) //save max value between current and provided
Countly.q.push(['userData.min', key, value]) //save min value between current and provided
Countly.q.push(['userData.push', key, value]) //add value to key as array element
Countly.q.push(['userData.push_unique', key, value]) //add value to key as array element, but only store unique values in array
Countly.q.push(['userData.pull', key, value]) //remove value from array under property with key as name
Countly.q.push(['userData.save']) //send userData to server
Countly.userData.set(key, value) //set custom property
Countly.userData.set_once(key, value) //set custom property only if property does not exist
Countly.userData.increment(key) //increment value in key by one
Countly.userData.increment_by(key, value) //increment value in key by provided value
Countly.userData.multiply(key, value) //multiply value in key by provided value
Countly.userData.max(key, value) //save max value between current and provided
Countly.userData.min(key, value) //save min value between current and provided
Countly.userData.push(key, value) //add value to key as array element
Countly.userData.push_unique(key, value) //add value to key as array element, but only store unique values in array
Countly.userData.pull(key, value) //remove value from array under property with key as name
Countly.userData.save() //send userData to server

Tracking Javascript errors

Countly also provides a way to track Javascript errors in your websites.

To automatically capture and report Javascript errors on your website, call the following function:

Countly.q.push(['track_errors'])
Countly.track_errors()

You can additionally add more segments or properties/values to track with error reports, by providing an object with key/values to add to error reports.

Countly.q.push(['track_errors', {
	"facebook_sdk": "2.3",
	"jquery": "1.8"
}])
Countly.track_errors({
	"facebook_sdk": "2.3",
	"jquery": "1.8"
})

Apart from reporting unhandled errors automatically, you can also report handled exceptions to server too, so you can figure out how and even if you need to handle them later on. And optionally you can again provide custom segments to be used in the report (or use the ones provided with track_error method as default ones)

Countly.log_error(error, segments);

try{
	//do something here
}
catch(ex){
	//report error to Countly
  Countly.q.push(['log_error', ex]);
}
try{
	//do something here
}
catch(ex){
	//report error to Countly
  Countly.log_error(ex);
}

To better understand what your users did prior to getting an error, you can leave out breadcrumbs through out the code, on different user actions. This breadcrumb will be then combined in single log and reported to server too.

Countly.q.push(['add_log', "user clicked button a"]);
Countly.add_log("user clicked button a");

Other methods

Changing Device ID

In some cases you may want to change the ID of the user/device that you provided or Countly generated automatically, for example, when user was changed.

Countly.q.push(['change_id', "myNewId"]);
Countly.change_id("myNewId");

In some cases, you may also need to change user's device ID in a way, that server will merge data of both user IDs (existing and new ID you provided) on the server, eg when user used website without authenticating and have recorded some data, and then authenticated and you want to change ID to your internal id of this user, to keep tracking it across multiple devices.

This call will merge any data recorded for current ID and save it as user with new provided ID.

Countly.q.push(['change_id', "myNewId", true]);
Countly.change_id("myNewId", true);

Tracking a session manually

Beginning a session

This method would allow you to control sessions manually. Use it only, if you don't call track_sessions method.

If noHeartBeat is true, then Countly WebSDK won't extend session automatically, and you would need to do that automatically.

Countly.q.push(['begin_session']);
Countly.begin_session(noHeartBeat);

Extending a session

By default (if noHeartBeat was not provided in begin_session) Countly SDK will extend session itself, but if you chose not to, then you can extend is using this method and provide seconds since last call begin_session or session_duration call, whatever was the last one.

Countly.q.push(['session_duration', sec]);
Countly.session_duration(sec)

Ending a session

When visitor is leaving your app or website, you should end his session with this method, optionally providing amount of seconds since last begin session or session_duration calls, whatever was the last one.

Countly.q.push(['end_session']);
Countly.end_session(sec)

Using Web SDK in Webview

If you are going to use Web SDK in the Webview of your app there are prerequisites to check to make it work fully. For now there are no known iOS issues, but some specific settings need to be enabled on Android.

  1. Make sure javascript is enabled for your webview
myWebView.getSettings().setJavaScriptEnabled(true);
  1. Make sure local storage is enabled
//change the path to where you want to store local storage data
myWebView.getSettings().setDomStorageEnabled(true);
myWebView.getSettings().setDatabaseEnabled(true);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
    myWebView.getSettings().setDatabasePath("/data/data/" + myWebView.getContext().getPackageName() + "/databases/");
}

If you want to use Countly both in native app and Webview, then you might also want to match device_id between them, so the transitions would be seamless and you just keep tracking events and data from both for the same user.

In this case there are couple of things you would want to do:

  1. Defer initializing Countly by putting initialization code in some function
  2. Not tracking sessions in webview, as they are tracked by native app either way
  3. Pass device_id to webview and run initialization function, once webview is loaded
<!--Countly script in webview-->
<script type='text/javascript'>
  var Countly = Countly || {};
	Countly.q = Countly.q || [];
  
	//provide countly initialization parameters
	Countly.app_key = "YOUR_APP_KEY";
	Countly.url = "http://yourdomain.com"; 
  
  //track views or anything else you want to track
	Countly.q.push(['track_pageview']);
  
	//function to initialize Countly
	function InitializeCountly(device_id) {
    
    //assign passed device_id
    Countly.device_id = device_id;
    
    //load countly script
		var cly = document.createElement('script'); cly.type = 'text/javascript'; 
		cly.async = true;
		//enter url of script here
		cly.src = 'https://cdn.jsdelivr.net/countly-sdk-web/latest/countly.min.js';
		cly.onload = function(){Countly.init()};
		var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(cly, s);
	};
</script>

Then on native app side all you have to do is to call javascript functions in the Webview and pass device_id to it

myWebView.loadUrl("javascript:InitializeCountly('"+device_id+"');");
#import "CountlyDeviceInfo.h"

NSString *js = [NSString stringWithFormat: @"InitializeCountly('%@');", CountlyDeviceInfo.sharedInstance.deviceID];
[myWebView stringByEvaluatingJavaScriptFromString:js];

Tracking users with Javascript disabled (available since 16.12)

In some cases user might have disabled Javascript, which means normal ways of tracking those users won't work. In that case you can use transparent 1px x 1px image hosted on your Countly server as reporting url and report all the same parameters as all SDKs described here.

So assuming your countly is hosted at domain.com and app_key is "12345", the default setup would look like this

<noscript><img src='http://domain.com/pixel.png?app_key=12345&begin_session=1'/></noscript>

Just put it anywhere in your HTML code and it would only work, if Javascript is disabled, which means SDK tracking won't work.

This would track how many sessions are users with disabled Javascript have in total. By default, server will attach device_id as no_js and add user profile name as No JS so you would easier identify how many users without Javascript you have.

But as mentioned before, it accepts any parameters as normal SDK endpoint /i does, so if you dynamically generate data by server, you can also dynamically generate this url, to provide information that you have about user, like device_id parameter to identify it, OS, OS version, and any other metrics or information you have, as for example

<noscript><img src='http://domain.com/pixel.png?app_key=12345&device_id=test@test.com&begin_session=1&metrics={"_os":"Android", "_os_version":"4.1"}'/></noscript>

Web Analytics (JavaScript)