{"__v":110,"_id":"55144edc1949d32d006afc9a","category":{"_id":"55a964c102becf2d007aad11","__v":7,"pages":["55a9652602becf2d007aad12","55a966cd5d3abb0d0012f25e","55b232ee23806c1900a9931d","55d1e56a3c74062300aee44a","55f537006dfd660d0072f90c","56d2c0855ad7ad0b00b7e865","56e1dfb9e63f910e00e598b5"],"project":"541c6d8251a68c3b45b9ada7","version":"541c6d8251a68c3b45b9adaa","sync":{"url":"","isSync":false},"reference":false,"createdAt":"2015-07-17T20:25:37.640Z","from_sync":false,"order":2,"slug":"official-sdks","title":"Official SDKs"},"parentDoc":null,"project":"541c6d8251a68c3b45b9ada7","user":"542e72631161420800d8353a","version":{"__v":16,"_id":"541c6d8251a68c3b45b9adaa","project":"541c6d8251a68c3b45b9ada7","createdAt":"2014-09-19T17:53:06.500Z","releaseDate":"2014-09-19T17:53:06.500Z","categories":["541c6d8251a68c3b45b9adab","541c6e1c51a68c3b45b9adae","542baa54e5bb3e2000801fec","5436794bb7cf0e1c0020d8cc","54367d76b7cf0e1c0020d8e9","54367dc7b7cf0e1c0020d8f4","54367defd0ffee0e00f18eb7","54368035b7cf0e1c0020d8fe","5436ad91b7cf0e1c0020da6c","5447a252a1024f14005a6dd7","547e0c858466c808005369a1","54f6b81852174719008f610b","5516d13c16a294230084a985","557971d4fdbdb717002fa6c1","55a964c102becf2d007aad11","55b8c26b1b56701900a14109"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"1.0.0","version":"1.0"},"updates":["55966163fdc90b0d003bc1a5"],"next":{"pages":[],"description":""},"createdAt":"2015-03-26T18:24:28.130Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":6,"body":"This documentation shows how to install Countly JS tracker and use Countly to track your web page in detail.\n\nIn 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.\n\nOptionally, you can also use package managers to get the library (but you don't have to, as it comes ready):\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"npm install countly-sdk-web\",\n      \"language\": \"shell\",\n      \"name\": \"npm\"\n    },\n    {\n      \"code\": \"bower install countly-sdk-web\",\n      \"language\": \"shell\",\n      \"name\": \"bower\"\n    }\n  ]\n}\n[/block]\nBefore 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. \n\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"What is an APP KEY?\",\n  \"body\": \"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.\\n\\nTo retrieve your APP_KEY, go to Management -> Applications and select your app, and you will see App Key field\"\n}\n[/block]\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/XmwUJ7VZSF2GConV76xY_app_key.png\",\n        \"app_key.png\",\n        \"613\",\n        \"464\",\n        \"#68988e\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Setting up (Recommended asynchronous usage)\"\n}\n[/block]\nYou 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.\n\nIt'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.\n\nExample setup would look like this:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<script type='text/javascript'>\\n  \\n//some default pre init\\nvar Countly = Countly || {};\\nCountly.q = Countly.q || [];\\n\\n//provide your app key that you retrieved from Countly dashboard\\nCountly.app_key = \\\"YOUR_APP_KEY\\\";\\n\\n//provide your server IP or name. Use try.count.ly for EE trial server.\\n//if you use your own server, make sure you have https enabled if you use\\n//https below.\\nCountly.url = \\\"https://yourdomain.com\\\"; \\n\\n//start pushing function calls to queue\\n//track sessions automatically\\nCountly.q.push(['track_sessions']);\\n  \\n//track sessions automatically\\nCountly.q.push(['track_pageview']);\\n  \\n//load countly script asynchronously\\n(function() {\\n\\tvar cly = document.createElement('script'); cly.type = 'text/javascript'; \\n\\tcly.async = true;\\n\\t//enter url of script here\\n\\tcly.src = 'https://cdn.jsdelivr.net/countly-sdk-web/latest/countly.min.js';\\n\\tcly.onload = function(){Countly.init()};\\n\\tvar s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(cly, s);\\n})();\\n</script>\",\n      \"language\": \"html\",\n      \"name\": \"Asynchronous\"\n    },\n    {\n      \"code\": \"<!--Countly script-->\\n<script type='text/javascript' src='https://cdn.jsdelivr.net/countly-sdk-web/latest/countly.min.js'></script>\\n<script type='text/javascript'>\\n\\nCountly.init({\\n//provide your app key that you retrieved from Countly dashboard\\n  \\tapp_key: \\\"YOUR_APP_KEY\\\",\\n\\n//provide your server IP or name. Use try.count.ly for EE trial server.\\n//if you use your own server, make sure you have https enabled if you use\\n//https below.\\n    url: \\\"http://yourdomain.com\\\" \\n    \\n\\t});\\n\\t//track sessions automatically\\n\\tCountly.track_sessions();\\n\\t//track pageviews automatically\\n\\tCountly.track_pageview();\\n</script>\",\n      \"language\": \"html\",\n      \"name\": \"Synchronous\"\n    }\n  ]\n}\n[/block]\nIn 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.\n[block:html]\n{\n  \"html\": \"<div>\\n  <p><label>cdnjs: </label><input onClick=\\\"this.select();\\\" type='text' value='https://cdnjs.cloudflare.com/ajax/libs/countly-sdk-web/16.6.0/countly.min.js' readonly class='cly-input'/></p>\\n  <p><label>jsDelivr: </label><input onClick=\\\"this.select();\\\" type='text' value='https://cdn.jsdelivr.net/countly-sdk-web/latest/countly.min.js' readonly class='cly-input'/></p>\\n</div>\\n\\n<style>\\n  .cly-input{\\n    border: 1px solid #cccccc;\\n    border-radius: 4px;\\n    width:100%;\\n    box-shadow: 0 0 0 3px #eee;\\n    padding: 4px;\\n  }\\n</style>\"\n}\n[/block]\nYou can also use '/sdk/web/countly.min.js' to get this SDK directly from your Countly server.\n\nAs the third alternative option, you can download [countly.min.js](https://github.com/Countly/countly-sdk-web/tree/master/lib) 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.\n\nAnd then you can make custom event calls like:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<script type='text/javascript'>\\n//send event on button click\\nfunction clickEvent(ob){\\n\\tCountly.q.push(['add_event',{\\n\\t\\tkey:\\\"asyncButtonClick\\\", \\n\\t\\tsegmentation: {\\n\\t\\t\\t\\\"id\\\": ob.id\\n\\t\\t}\\n\\t}]);\\n}\\n</script>\\n<input type=\\\"button\\\" id=\\\"asyncTestButton\\\" onclick=\\\"clickEvent(this)\\\" value=\\\"Test Button\\\">\",\n      \"language\": \"html\",\n      \"name\": \"Asynchronous\"\n    },\n    {\n      \"code\": \"<script type='text/javascript'>\\n  //send event on button click\\n  function clickEvent(ob){\\n    Countly.add_event({\\n      key:\\\"buttonClick\\\", \\n      segmentation: {\\n        \\\"id\\\": ob.id\\n      }\\n    });\\n  }\\n</script>\\n<input type=\\\"button\\\" id=\\\"testButton\\\" onclick=\\\"clickEvent(this)\\\" value=\\\"Test Button\\\">\",\n      \"language\": \"html\",\n      \"name\": \"Synchronous\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Setup properties\"\n}\n[/block]\nHere are the properties you can setup on Countly initialization\n\n  * **app_key** - mandatory, app key for your app created in Countly\n  * **device_id** - to identify a visitor, will be auto generated if not provided\n  * **url** - your Countly server url - you can also use your own server URL or IP here\n  * **app_version** -  (optional) the version of your app or website\n  * **country_code** - (optional) country code for your visitor\n  * **city** - (optional) name of the city of your visitor\n  * **ip_address** - (optional) ip address of your visitor\n  * **debug** - output debug info into console (default: false)\n  * **ignore_bots** - option to ignore traffic from bots (default: true)\n  * **interval** - set an interval how often to check if there is any data to report and report it (default: 500 ms)\n  * **fail_timeout** - set time in seconds to wait after failed connection to server (default: 60 seconds)\n\nSetting up properties in Countly Web SDK is as follows (use your own server name if not using try.count.ly below):\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"Countly.debug = false;\\nCountly.app_key = \\\"YOUR_APP_KEY\\\";\\nCountly.device_id = \\\"1234-1234-1234-1234\\\";\\nCountly.url = \\\"https://try.count.ly\\\";\\nCountly.app_version = \\\"1.2\\\";\\nCountly.country_code = \\\"LV\\\";\\nCountly.city = \\\"Riga\\\";\\nCountly.ip_address = \\\"83.140.15.1\\\";\",\n      \"language\": \"javascript\",\n      \"name\": \"Asynchronous\"\n    },\n    {\n      \"code\": \"Countly.init({\\n\\t\\t\\tdebug:false,\\n\\t\\t\\tapp_key:\\\"YOUR_APP_KEY\\\",\\n\\t\\t\\tdevice_id:\\\"1234-1234-1234-1234\\\",\\n\\t\\t\\turl: \\\"https://cloud.count.ly\\\",\\n\\t\\t\\tapp_version: \\\"1.2\\\",\\n\\t\\t\\tcountry_code: \\\"LV\\\",\\n\\t\\t\\tcity: \\\"Riga\\\",\\n\\t\\t\\tip_address: \\\"83.140.15.1\\\"\\n\\t\\t}\\n});\",\n      \"language\": \"javascript\",\n      \"name\": \"Synchronous\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Helper methods\"\n}\n[/block]\nHelper methods created to allow you easily track most common actions on the web.\n\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"title\": \"Choose your helper methods carefully\",\n  \"body\": \"Helper methods we provide below are both for synchronous and asynchronous tracking code. Choose the right helper method depending on your implementation.\"\n}\n[/block]\n###Track Sessions###\n\nThis method will automatically track user sessions, by calling begin extend and end session methods\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"Countly.q.push(['track_sessions']);\",\n      \"language\": \"javascript\",\n      \"name\": \"Asynchronous\"\n    },\n    {\n      \"code\": \"Countly.track_sessions();\",\n      \"language\": \"javascript\",\n      \"name\": \"Synchronous\"\n    }\n  ]\n}\n[/block]\n###Track Pageviews###\n\nThis method will track current pageview, by using location.path as page name and report it to server\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"Countly.q.push(['track_pageview']);\",\n      \"language\": \"javascript\",\n      \"name\": \"Asynchronous\"\n    },\n    {\n      \"code\": \"Countly.track_pageview();\",\n      \"language\": \"javascript\",\n      \"name\": \"Synchronous\"\n    }\n  ]\n}\n[/block]\nFor Ajax updated contents and single page web applications, pass page name as a parameter to record new page view\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"Countly.q.push(['track_pageview','pagename']);\",\n      \"language\": \"javascript\",\n      \"name\": \"Asynchronous\"\n    },\n    {\n      \"code\": \"Countly.track_pageview(\\\"pagename\\\");\",\n      \"language\": \"javascript\",\n      \"name\": \"Synchronous\"\n    }\n  ]\n}\n[/block]\n###Track Clicks (Enterprise edition)###\n\nThis method will automatically track clicks on last reported view and display them on the heat map\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"Countly.q.push(['track_clicks']);\",\n      \"language\": \"javascript\",\n      \"name\": \"Asynchronous\"\n    },\n    {\n      \"code\": \"Countly.track_clicks();\",\n      \"language\": \"javascript\",\n      \"name\": \"Synchronous\"\n    }\n  ]\n}\n[/block]\n###Track Link clicks###\n\nThis 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. \n\nBy 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\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"Countly.q.push(['track_links']);\",\n      \"language\": \"javascript\",\n      \"name\": \"Asynchronous\"\n    },\n    {\n      \"code\": \"Countly.track_links();\",\n      \"language\": \"javascript\",\n      \"name\": \"Synchronous\"\n    }\n  ]\n}\n[/block]\n###Track Form Submissions###\n\nThis method will automatically track form submissions and collect form data and input values in the form and report as Custom Event with **formSubmit** key\n\nBy default all forms would be tracked for whole page, but you may provide the parent node as a parameter for which to track forms.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"Countly.q.push(['track_forms']);\",\n      \"language\": \"javascript\",\n      \"name\": \"Asynchronous\"\n    },\n    {\n      \"code\": \"Countly.track_forms();\",\n      \"language\": \"javascript\",\n      \"name\": \"Synchronous\"\n    }\n  ]\n}\n[/block]\n###Report conversion###\n\nWhen using Countly attribution analytics, you can also report conversion to Countly server, like for example when visitor purchased something or registered.\n\nBy 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. \n\nBut you can also overwrite that data and provide some specific campaign id for which you want to report conversion.\n\nIf there is no stored campaign data and you don't provide any campaign id, then conversion will not be reported.\n\nNote: that conversion for each user may be reported only once, all other conversions will be ignored for this same user\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"//user stored conversion data\\nCountly.q.push(['report_conversion']);\\n\\n//or provide campaign id yourself\\nCountly.q.push(['report_conversion', \\\"MyCampaignID\\\"]);\",\n      \"language\": \"javascript\",\n      \"name\": \"Asynchronous\"\n    },\n    {\n      \"code\": \"//user stored conversion data\\nCountly.report_conversion();\\n\\n//or provide campaign id yourself\\nCountly.report_conversion(\\\"MyCampaignID\\\");\",\n      \"language\": \"javascript\",\n      \"name\": \"Synchronous\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Custom Events\"\n}\n[/block]\n###Adding an event###\n\nCustom 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.\n\nCustom event consists of Javascript object with keys:\n* key - the name of the event (mandatory)\n* count - number of events (default: 1)\n* sum - sum to report with event (optional)\n* dur - duration to report with event (optional)\n* segmentation - an object with key/value pairs to report with event as segments\n\nHere is an example of adding a custom event with all possible properties:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"Countly.q.push(['add_event',{\\n\\t\\\"key\\\": \\\"click\\\",\\n  \\\"count\\\": 1,\\n  \\\"sum\\\": 1.5,\\n  \\\"dur\\\": 30,\\n\\t\\\"segmentation\\\": {\\n    \\\"key1\\\": \\\"value1\\\",\\n    \\\"key2\\\": \\\"value2\\\"\\n\\t}\\n}]);\",\n      \"language\": \"javascript\",\n      \"name\": \"Asynchronous\"\n    },\n    {\n      \"code\": \"Countly.add_event({\\n\\t\\\"key\\\": \\\"click\\\",\\n  \\\"count\\\": 1,\\n  \\\"sum\\\": 1.5,\\n  \\\"dur\\\": 30,\\n\\t\\\"segmentation\\\": {\\n    \\\"key1\\\": \\\"value1\\\",\\n    \\\"key2\\\": \\\"value2\\\"\\n\\t}\\n});\",\n      \"language\": \"javascript\",\n      \"name\": \"Synchronous\"\n    }\n  ]\n}\n[/block]\n###Timed Events###\n\nYou 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.\n\nFirstly you can start tracking event time by providing name of the event (which later on will be used as key for event object)\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"Countly.q.push(['start_event', 'timedEvent']);\",\n      \"language\": \"javascript\",\n      \"name\": \"Asynchronous\"\n    },\n    {\n      \"code\": \"Countly.start_event(\\\"timedEvent\\\")\",\n      \"language\": \"javascript\",\n      \"name\": \"Synchronous\"\n    }\n  ]\n}\n[/block]\nCountly 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.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"//end event\\nCountly.q.push(['end_event', 'timedEvent']);\\n\\n//or end event with additional data\\nCountly.q.push(['end_event',{\\n\\t\\\"key\\\": \\\"timedEvent\\\",\\n  \\\"count\\\": 1,\\n  \\\"sum\\\": 1.5,\\n\\t\\\"segmentation\\\": {\\n    \\\"key1\\\": \\\"value1\\\",\\n    \\\"key2\\\": \\\"value2\\\"\\n\\t}\\n}]);\",\n      \"language\": \"javascript\",\n      \"name\": \"Asynchronous\"\n    },\n    {\n      \"code\": \"//end event\\nCountly.end_event(\\\"timedEvent\\\")\\n\\n//or end event with additional data\\nCountly.end_event({\\n\\t\\\"key\\\": \\\"timedEvent\\\",\\n  \\\"count\\\": 1,\\n  \\\"sum\\\": 1.5,\\n\\t\\\"segmentation\\\": {\\n    \\\"key1\\\": \\\"value1\\\",\\n    \\\"key2\\\": \\\"value2\\\"\\n\\t}\\n});\",\n      \"language\": \"javascript\",\n      \"name\": \"Synchronous\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"User Profiles and Custom data\"\n}\n[/block]\n###User details###\n\nIf 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](http://count.ly/enterprise-edition).\n\nThe list of possible parameters you can pass is:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"Countly.q.push(['user_details',{\\n    \\\"name\\\": \\\"Arturs Sosins\\\",\\n    \\\"username\\\": \\\"ar2rsawseen\\\",\\n    \\\"email\\\": \\\"test:::at:::test.com\\\",\\n    \\\"organization\\\": \\\"Countly\\\",\\n    \\\"phone\\\": \\\"+37112345678\\\",\\n    //Web URL to picture\\n    \\\"picture\\\": \\\"https://pbs.twimg.com/profile_images/1442562237/012_n_400x400.jpg\\\", \\n    \\\"gender\\\": \\\"M\\\",\\n    \\\"byear\\\": 1987, //birth year\\n    \\\"custom\\\":{\\n      \\\"key1\\\":\\\"value1\\\",\\n      \\\"key2\\\":\\\"value2\\\",\\n      ...\\n    }\\n}]);\",\n      \"language\": \"javascript\",\n      \"name\": \"Asynchronous\"\n    },\n    {\n      \"code\": \"Countly.user_details({\\n    \\\"name\\\": \\\"Arturs Sosins\\\",\\n    \\\"username\\\": \\\"ar2rsawseen\\\",\\n    \\\"email\\\": \\\"test@test.com\\\",\\n    \\\"organization\\\": \\\"Countly\\\",\\n    \\\"phone\\\": \\\"+37112345678\\\",\\n    //Web URL pointing to user picture\\n    \\\"picture\\\": \\\"https://pbs.twimg.com/profile_images/1442562237/012_n_400x400.jpg\\\", \\n    \\\"gender\\\": \\\"M\\\",\\n    \\\"byear\\\": 1987, //birth year\\n    \\\"custom\\\":{\\n      \\\"key1\\\":\\\"value1\\\",\\n      \\\"key2\\\":\\\"value2\\\",\\n      ...\\n    }\\n });\",\n      \"language\": \"javascript\",\n      \"name\": \"Synchronous\"\n    }\n  ]\n}\n[/block]\n###Modifying custom data###\n\nAdditionally you can do different manipulations on custom data values, like increment current value on server or store array of values under same property.\n\nBelow is the list of available methods:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"Countly.q.push(['userData.set', key, value]) //set custom property\\nCountly.q.push(['userData.set_once', key, value]) //set custom property only if property does not exist\\nCountly.q.push(['userData.increment', key]) //increment value in key by one\\nCountly.q.push(['userData.increment_by', key, value]) //increment value in key by provided value\\nCountly.q.push(['userData.multiply', key, value]) //multiply value in key by provided value\\nCountly.q.push(['userData.max', key, value]) //save max value between current and provided\\nCountly.q.push(['userData.min', key, value]) //save min value between current and provided\\nCountly.q.push(['userData.push', key, value]) //add value to key as array element\\nCountly.q.push(['userData.push_unique', key, value]) //add value to key as array element, but only store unique values in array\\nCountly.q.push(['userData.pull', key, value]) //remove value from array under property with key as name\\nCountly.q.push(['userData.save']) //send userData to server\",\n      \"language\": \"javascript\",\n      \"name\": \"Asynchronous\"\n    },\n    {\n      \"code\": \"Countly.userData.set(key, value) //set custom property\\nCountly.userData.set_once(key, value) //set custom property only if property does not exist\\nCountly.userData.increment(key) //increment value in key by one\\nCountly.userData.increment_by(key, value) //increment value in key by provided value\\nCountly.userData.multiply(key, value) //multiply value in key by provided value\\nCountly.userData.max(key, value) //save max value between current and provided\\nCountly.userData.min(key, value) //save min value between current and provided\\nCountly.userData.push(key, value) //add value to key as array element\\nCountly.userData.push_unique(key, value) //add value to key as array element, but only store unique values in array\\nCountly.userData.pull(key, value) //remove value from array under property with key as name\\nCountly.userData.save() //send userData to server\",\n      \"language\": \"javascript\",\n      \"name\": \"Synchronous\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Tracking Javascript errors\"\n}\n[/block]\nCountly also provides a way to track Javascript errors in your websites.\n\nTo automatically capture and report Javascript errors on your website, call the following function:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"Countly.q.push(['track_errors'])\",\n      \"language\": \"javascript\",\n      \"name\": \"Asynchronous\"\n    },\n    {\n      \"code\": \"Countly.track_errors()\",\n      \"language\": \"javascript\",\n      \"name\": \"Synchronous\"\n    }\n  ]\n}\n[/block]\nYou 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.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"Countly.q.push(['track_errors', {\\n\\t\\\"facebook_sdk\\\": \\\"2.3\\\",\\n\\t\\\"jquery\\\": \\\"1.8\\\"\\n}])\",\n      \"language\": \"javascript\",\n      \"name\": \"Asynchronous\"\n    },\n    {\n      \"code\": \"Countly.track_errors({\\n\\t\\\"facebook_sdk\\\": \\\"2.3\\\",\\n\\t\\\"jquery\\\": \\\"1.8\\\"\\n})\",\n      \"language\": \"javascript\",\n      \"name\": \"Synchronous\"\n    }\n  ]\n}\n[/block]\nApart 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)\n\n**Countly.log_error(error, segments);** \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"try{\\n\\t//do something here\\n}\\ncatch(ex){\\n\\t//report error to Countly\\n  Countly.q.push(['log_error', ex]);\\n}\",\n      \"language\": \"javascript\",\n      \"name\": \"Asynchronous\"\n    },\n    {\n      \"code\": \"try{\\n\\t//do something here\\n}\\ncatch(ex){\\n\\t//report error to Countly\\n  Countly.log_error(ex);\\n}\",\n      \"language\": \"javascript\",\n      \"name\": \"Synchronous\"\n    }\n  ]\n}\n[/block]\nTo 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.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"Countly.q.push(['add_log', \\\"user clicked button a\\\"]);\",\n      \"language\": \"javascript\",\n      \"name\": \"Asynchronous\"\n    },\n    {\n      \"code\": \"Countly.add_log(\\\"user clicked button a\\\");\",\n      \"language\": \"javascript\",\n      \"name\": \"Synchronous\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Other methods\"\n}\n[/block]\n###Changing Device ID###\n\nIn 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.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"Countly.q.push(['change_id', \\\"myNewId\\\"]);\",\n      \"language\": \"javascript\",\n      \"name\": \"Asynchronous\"\n    },\n    {\n      \"code\": \"Countly.change_id(\\\"myNewId\\\");\",\n      \"language\": \"javascript\",\n      \"name\": \"Synchronous\"\n    }\n  ]\n}\n[/block]\nIn 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.\n\nThis call will merge any data recorded for current ID and save it as user with new provided ID.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"Countly.q.push(['change_id', \\\"myNewId\\\", true]);\",\n      \"language\": \"javascript\",\n      \"name\": \"Asynchronous\"\n    },\n    {\n      \"code\": \"Countly.change_id(\\\"myNewId\\\", true);\",\n      \"language\": \"javascript\",\n      \"name\": \"Synchronous\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Tracking a session manually\"\n}\n[/block]\n###Beginning a session###\n\nThis method would allow you to control sessions manually. Use it only, if you don't call track_sessions method.\n\nIf **noHeartBeat** is true, then Countly WebSDK won't extend session automatically, and you would need to do that automatically.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"Countly.q.push(['begin_session']);\",\n      \"language\": \"javascript\",\n      \"name\": \"Asynchronous\"\n    },\n    {\n      \"code\": \"Countly.begin_session(noHeartBeat);\",\n      \"language\": \"javascript\",\n      \"name\": \"Synchronous\"\n    }\n  ]\n}\n[/block]\n###Extending a session###\n\nBy 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.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"Countly.q.push(['session_duration', sec]);\",\n      \"language\": \"javascript\",\n      \"name\": \"Asynchronous\"\n    },\n    {\n      \"code\": \"Countly.session_duration(sec)\",\n      \"language\": \"javascript\",\n      \"name\": \"Synchronous\"\n    }\n  ]\n}\n[/block]\n###Ending a session###\n\nWhen 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.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"Countly.q.push(['end_session']);\",\n      \"language\": \"javascript\",\n      \"name\": \"Asynchronous\"\n    },\n    {\n      \"code\": \"Countly.end_session(sec)\",\n      \"language\": \"javascript\",\n      \"name\": \"Synchronous\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Using Web SDK in Webview\"\n}\n[/block]\nIf 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.\n\n1. Make sure javascript is enabled for your webview\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"myWebView.getSettings().setJavaScriptEnabled(true);\",\n      \"language\": \"java\",\n      \"name\": \"Android\"\n    }\n  ]\n}\n[/block]\n2. Make sure local storage is enabled\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"//change the path to where you want to store local storage data\\nmyWebView.getSettings().setDomStorageEnabled(true);\\nmyWebView.getSettings().setDatabaseEnabled(true);\\nif (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {\\n    myWebView.getSettings().setDatabasePath(\\\"/data/data/\\\" + myWebView.getContext().getPackageName() + \\\"/databases/\\\");\\n}\",\n      \"language\": \"java\",\n      \"name\": \"Android\"\n    }\n  ]\n}\n[/block]\nIf 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.\n\nIn this case there are couple of things you would want to do:\n1. Defer initializing Countly by putting initialization code in some function\n2. Not tracking sessions in webview, as they are tracked by native app either way\n3. Pass device_id to webview and run initialization function, once webview is loaded\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<!--Countly script in webview-->\\n<script type='text/javascript'>\\n  var Countly = Countly || {};\\n\\tCountly.q = Countly.q || [];\\n  \\n\\t//provide countly initialization parameters\\n\\tCountly.app_key = \\\"YOUR_APP_KEY\\\";\\n\\tCountly.url = \\\"http://yourdomain.com\\\"; \\n  \\n  //track views or anything else you want to track\\n\\tCountly.q.push(['track_pageview']);\\n  \\n\\t//function to initialize Countly\\n\\tfunction InitializeCountly(device_id) {\\n    \\n    //assign passed device_id\\n    Countly.device_id = device_id;\\n    \\n    //load countly script\\n\\t\\tvar cly = document.createElement('script'); cly.type = 'text/javascript'; \\n\\t\\tcly.async = true;\\n\\t\\t//enter url of script here\\n\\t\\tcly.src = 'https://cdn.jsdelivr.net/countly-sdk-web/latest/countly.min.js';\\n\\t\\tcly.onload = function(){Countly.init()};\\n\\t\\tvar s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(cly, s);\\n\\t};\\n</script>\",\n      \"language\": \"html\",\n      \"name\": \"WebView\"\n    }\n  ]\n}\n[/block]\nThen on native app side all you have to do is to call javascript functions in the Webview and pass device_id to it\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"myWebView.loadUrl(\\\"javascript:InitializeCountly('\\\"+device_id+\\\"');\\\");\",\n      \"language\": \"java\",\n      \"name\": \"Android\"\n    },\n    {\n      \"code\": \"#import \\\"CountlyDeviceInfo.h\\\"\\n\\nNSString *js = [NSString stringWithFormat: @\\\"InitializeCountly('%@');\\\", CountlyDeviceInfo.sharedInstance.deviceID];\\n[myWebView stringByEvaluatingJavaScriptFromString:js];\",\n      \"language\": \"objectivec\",\n      \"name\": \"iOS\"\n    }\n  ]\n}\n[/block]","excerpt":"","slug":"countly-sdk-for-web","type":"basic","title":"Web Analytics (JavaScript)"}

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): [block:code] { "codes": [ { "code": "npm install countly-sdk-web", "language": "shell", "name": "npm" }, { "code": "bower install countly-sdk-web", "language": "shell", "name": "bower" } ] } [/block] 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. [block:callout] { "type": "info", "title": "What is an APP KEY?", "body": "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.\n\nTo retrieve your APP_KEY, go to Management -> Applications and select your app, and you will see App Key field" } [/block] [block:image] { "images": [ { "image": [ "https://files.readme.io/XmwUJ7VZSF2GConV76xY_app_key.png", "app_key.png", "613", "464", "#68988e", "" ] } ] } [/block] [block:api-header] { "type": "basic", "title": "Setting up (Recommended asynchronous usage)" } [/block] 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: [block:code] { "codes": [ { "code": "<script type='text/javascript'>\n \n//some default pre init\nvar Countly = Countly || {};\nCountly.q = Countly.q || [];\n\n//provide your app key that you retrieved from Countly dashboard\nCountly.app_key = \"YOUR_APP_KEY\";\n\n//provide your server IP or name. Use try.count.ly for EE trial server.\n//if you use your own server, make sure you have https enabled if you use\n//https below.\nCountly.url = \"https://yourdomain.com\"; \n\n//start pushing function calls to queue\n//track sessions automatically\nCountly.q.push(['track_sessions']);\n \n//track sessions automatically\nCountly.q.push(['track_pageview']);\n \n//load countly script asynchronously\n(function() {\n\tvar cly = document.createElement('script'); cly.type = 'text/javascript'; \n\tcly.async = true;\n\t//enter url of script here\n\tcly.src = 'https://cdn.jsdelivr.net/countly-sdk-web/latest/countly.min.js';\n\tcly.onload = function(){Countly.init()};\n\tvar s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(cly, s);\n})();\n</script>", "language": "html", "name": "Asynchronous" }, { "code": "<!--Countly script-->\n<script type='text/javascript' src='https://cdn.jsdelivr.net/countly-sdk-web/latest/countly.min.js'></script>\n<script type='text/javascript'>\n\nCountly.init({\n//provide your app key that you retrieved from Countly dashboard\n \tapp_key: \"YOUR_APP_KEY\",\n\n//provide your server IP or name. Use try.count.ly for EE trial server.\n//if you use your own server, make sure you have https enabled if you use\n//https below.\n url: \"http://yourdomain.com\" \n \n\t});\n\t//track sessions automatically\n\tCountly.track_sessions();\n\t//track pageviews automatically\n\tCountly.track_pageview();\n</script>", "language": "html", "name": "Synchronous" } ] } [/block] 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. [block:html] { "html": "<div>\n <p><label>cdnjs: </label><input onClick=\"this.select();\" type='text' value='https://cdnjs.cloudflare.com/ajax/libs/countly-sdk-web/16.6.0/countly.min.js' readonly class='cly-input'/></p>\n <p><label>jsDelivr: </label><input onClick=\"this.select();\" type='text' value='https://cdn.jsdelivr.net/countly-sdk-web/latest/countly.min.js' readonly class='cly-input'/></p>\n</div>\n\n<style>\n .cly-input{\n border: 1px solid #cccccc;\n border-radius: 4px;\n width:100%;\n box-shadow: 0 0 0 3px #eee;\n padding: 4px;\n }\n</style>" } [/block] 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](https://github.com/Countly/countly-sdk-web/tree/master/lib) 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: [block:code] { "codes": [ { "code": "<script type='text/javascript'>\n//send event on button click\nfunction clickEvent(ob){\n\tCountly.q.push(['add_event',{\n\t\tkey:\"asyncButtonClick\", \n\t\tsegmentation: {\n\t\t\t\"id\": ob.id\n\t\t}\n\t}]);\n}\n</script>\n<input type=\"button\" id=\"asyncTestButton\" onclick=\"clickEvent(this)\" value=\"Test Button\">", "language": "html", "name": "Asynchronous" }, { "code": "<script type='text/javascript'>\n //send event on button click\n function clickEvent(ob){\n Countly.add_event({\n key:\"buttonClick\", \n segmentation: {\n \"id\": ob.id\n }\n });\n }\n</script>\n<input type=\"button\" id=\"testButton\" onclick=\"clickEvent(this)\" value=\"Test Button\">", "language": "html", "name": "Synchronous" } ] } [/block] [block:api-header] { "type": "basic", "title": "Setup properties" } [/block] 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): [block:code] { "codes": [ { "code": "Countly.debug = false;\nCountly.app_key = \"YOUR_APP_KEY\";\nCountly.device_id = \"1234-1234-1234-1234\";\nCountly.url = \"https://try.count.ly\";\nCountly.app_version = \"1.2\";\nCountly.country_code = \"LV\";\nCountly.city = \"Riga\";\nCountly.ip_address = \"83.140.15.1\";", "language": "javascript", "name": "Asynchronous" }, { "code": "Countly.init({\n\t\t\tdebug:false,\n\t\t\tapp_key:\"YOUR_APP_KEY\",\n\t\t\tdevice_id:\"1234-1234-1234-1234\",\n\t\t\turl: \"https://cloud.count.ly\",\n\t\t\tapp_version: \"1.2\",\n\t\t\tcountry_code: \"LV\",\n\t\t\tcity: \"Riga\",\n\t\t\tip_address: \"83.140.15.1\"\n\t\t}\n});", "language": "javascript", "name": "Synchronous" } ] } [/block] [block:api-header] { "type": "basic", "title": "Helper methods" } [/block] Helper methods created to allow you easily track most common actions on the web. [block:callout] { "type": "warning", "title": "Choose your helper methods carefully", "body": "Helper methods we provide below are both for synchronous and asynchronous tracking code. Choose the right helper method depending on your implementation." } [/block] ###Track Sessions### This method will automatically track user sessions, by calling begin extend and end session methods [block:code] { "codes": [ { "code": "Countly.q.push(['track_sessions']);", "language": "javascript", "name": "Asynchronous" }, { "code": "Countly.track_sessions();", "language": "javascript", "name": "Synchronous" } ] } [/block] ###Track Pageviews### This method will track current pageview, by using location.path as page name and report it to server [block:code] { "codes": [ { "code": "Countly.q.push(['track_pageview']);", "language": "javascript", "name": "Asynchronous" }, { "code": "Countly.track_pageview();", "language": "javascript", "name": "Synchronous" } ] } [/block] For Ajax updated contents and single page web applications, pass page name as a parameter to record new page view [block:code] { "codes": [ { "code": "Countly.q.push(['track_pageview','pagename']);", "language": "javascript", "name": "Asynchronous" }, { "code": "Countly.track_pageview(\"pagename\");", "language": "javascript", "name": "Synchronous" } ] } [/block] ###Track Clicks (Enterprise edition)### This method will automatically track clicks on last reported view and display them on the heat map [block:code] { "codes": [ { "code": "Countly.q.push(['track_clicks']);", "language": "javascript", "name": "Asynchronous" }, { "code": "Countly.track_clicks();", "language": "javascript", "name": "Synchronous" } ] } [/block] ###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 [block:code] { "codes": [ { "code": "Countly.q.push(['track_links']);", "language": "javascript", "name": "Asynchronous" }, { "code": "Countly.track_links();", "language": "javascript", "name": "Synchronous" } ] } [/block] ###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. [block:code] { "codes": [ { "code": "Countly.q.push(['track_forms']);", "language": "javascript", "name": "Asynchronous" }, { "code": "Countly.track_forms();", "language": "javascript", "name": "Synchronous" } ] } [/block] ###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 [block:code] { "codes": [ { "code": "//user stored conversion data\nCountly.q.push(['report_conversion']);\n\n//or provide campaign id yourself\nCountly.q.push(['report_conversion', \"MyCampaignID\"]);", "language": "javascript", "name": "Asynchronous" }, { "code": "//user stored conversion data\nCountly.report_conversion();\n\n//or provide campaign id yourself\nCountly.report_conversion(\"MyCampaignID\");", "language": "javascript", "name": "Synchronous" } ] } [/block] [block:api-header] { "type": "basic", "title": "Custom Events" } [/block] ###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: [block:code] { "codes": [ { "code": "Countly.q.push(['add_event',{\n\t\"key\": \"click\",\n \"count\": 1,\n \"sum\": 1.5,\n \"dur\": 30,\n\t\"segmentation\": {\n \"key1\": \"value1\",\n \"key2\": \"value2\"\n\t}\n}]);", "language": "javascript", "name": "Asynchronous" }, { "code": "Countly.add_event({\n\t\"key\": \"click\",\n \"count\": 1,\n \"sum\": 1.5,\n \"dur\": 30,\n\t\"segmentation\": {\n \"key1\": \"value1\",\n \"key2\": \"value2\"\n\t}\n});", "language": "javascript", "name": "Synchronous" } ] } [/block] ###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) [block:code] { "codes": [ { "code": "Countly.q.push(['start_event', 'timedEvent']);", "language": "javascript", "name": "Asynchronous" }, { "code": "Countly.start_event(\"timedEvent\")", "language": "javascript", "name": "Synchronous" } ] } [/block] 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. [block:code] { "codes": [ { "code": "//end event\nCountly.q.push(['end_event', 'timedEvent']);\n\n//or end event with additional data\nCountly.q.push(['end_event',{\n\t\"key\": \"timedEvent\",\n \"count\": 1,\n \"sum\": 1.5,\n\t\"segmentation\": {\n \"key1\": \"value1\",\n \"key2\": \"value2\"\n\t}\n}]);", "language": "javascript", "name": "Asynchronous" }, { "code": "//end event\nCountly.end_event(\"timedEvent\")\n\n//or end event with additional data\nCountly.end_event({\n\t\"key\": \"timedEvent\",\n \"count\": 1,\n \"sum\": 1.5,\n\t\"segmentation\": {\n \"key1\": \"value1\",\n \"key2\": \"value2\"\n\t}\n});", "language": "javascript", "name": "Synchronous" } ] } [/block] [block:api-header] { "type": "basic", "title": "User Profiles and Custom data" } [/block] ###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](http://count.ly/enterprise-edition). The list of possible parameters you can pass is: [block:code] { "codes": [ { "code": "Countly.q.push(['user_details',{\n \"name\": \"Arturs Sosins\",\n \"username\": \"ar2rsawseen\",\n \"email\": \"test@test.com\",\n \"organization\": \"Countly\",\n \"phone\": \"+37112345678\",\n //Web URL to picture\n \"picture\": \"https://pbs.twimg.com/profile_images/1442562237/012_n_400x400.jpg\", \n \"gender\": \"M\",\n \"byear\": 1987, //birth year\n \"custom\":{\n \"key1\":\"value1\",\n \"key2\":\"value2\",\n ...\n }\n}]);", "language": "javascript", "name": "Asynchronous" }, { "code": "Countly.user_details({\n \"name\": \"Arturs Sosins\",\n \"username\": \"ar2rsawseen\",\n \"email\": \"test@test.com\",\n \"organization\": \"Countly\",\n \"phone\": \"+37112345678\",\n //Web URL pointing to user picture\n \"picture\": \"https://pbs.twimg.com/profile_images/1442562237/012_n_400x400.jpg\", \n \"gender\": \"M\",\n \"byear\": 1987, //birth year\n \"custom\":{\n \"key1\":\"value1\",\n \"key2\":\"value2\",\n ...\n }\n });", "language": "javascript", "name": "Synchronous" } ] } [/block] ###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: [block:code] { "codes": [ { "code": "Countly.q.push(['userData.set', key, value]) //set custom property\nCountly.q.push(['userData.set_once', key, value]) //set custom property only if property does not exist\nCountly.q.push(['userData.increment', key]) //increment value in key by one\nCountly.q.push(['userData.increment_by', key, value]) //increment value in key by provided value\nCountly.q.push(['userData.multiply', key, value]) //multiply value in key by provided value\nCountly.q.push(['userData.max', key, value]) //save max value between current and provided\nCountly.q.push(['userData.min', key, value]) //save min value between current and provided\nCountly.q.push(['userData.push', key, value]) //add value to key as array element\nCountly.q.push(['userData.push_unique', key, value]) //add value to key as array element, but only store unique values in array\nCountly.q.push(['userData.pull', key, value]) //remove value from array under property with key as name\nCountly.q.push(['userData.save']) //send userData to server", "language": "javascript", "name": "Asynchronous" }, { "code": "Countly.userData.set(key, value) //set custom property\nCountly.userData.set_once(key, value) //set custom property only if property does not exist\nCountly.userData.increment(key) //increment value in key by one\nCountly.userData.increment_by(key, value) //increment value in key by provided value\nCountly.userData.multiply(key, value) //multiply value in key by provided value\nCountly.userData.max(key, value) //save max value between current and provided\nCountly.userData.min(key, value) //save min value between current and provided\nCountly.userData.push(key, value) //add value to key as array element\nCountly.userData.push_unique(key, value) //add value to key as array element, but only store unique values in array\nCountly.userData.pull(key, value) //remove value from array under property with key as name\nCountly.userData.save() //send userData to server", "language": "javascript", "name": "Synchronous" } ] } [/block] [block:api-header] { "type": "basic", "title": "Tracking Javascript errors" } [/block] 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: [block:code] { "codes": [ { "code": "Countly.q.push(['track_errors'])", "language": "javascript", "name": "Asynchronous" }, { "code": "Countly.track_errors()", "language": "javascript", "name": "Synchronous" } ] } [/block] 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. [block:code] { "codes": [ { "code": "Countly.q.push(['track_errors', {\n\t\"facebook_sdk\": \"2.3\",\n\t\"jquery\": \"1.8\"\n}])", "language": "javascript", "name": "Asynchronous" }, { "code": "Countly.track_errors({\n\t\"facebook_sdk\": \"2.3\",\n\t\"jquery\": \"1.8\"\n})", "language": "javascript", "name": "Synchronous" } ] } [/block] 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);** [block:code] { "codes": [ { "code": "try{\n\t//do something here\n}\ncatch(ex){\n\t//report error to Countly\n Countly.q.push(['log_error', ex]);\n}", "language": "javascript", "name": "Asynchronous" }, { "code": "try{\n\t//do something here\n}\ncatch(ex){\n\t//report error to Countly\n Countly.log_error(ex);\n}", "language": "javascript", "name": "Synchronous" } ] } [/block] 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. [block:code] { "codes": [ { "code": "Countly.q.push(['add_log', \"user clicked button a\"]);", "language": "javascript", "name": "Asynchronous" }, { "code": "Countly.add_log(\"user clicked button a\");", "language": "javascript", "name": "Synchronous" } ] } [/block] [block:api-header] { "type": "basic", "title": "Other methods" } [/block] ###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. [block:code] { "codes": [ { "code": "Countly.q.push(['change_id', \"myNewId\"]);", "language": "javascript", "name": "Asynchronous" }, { "code": "Countly.change_id(\"myNewId\");", "language": "javascript", "name": "Synchronous" } ] } [/block] 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. [block:code] { "codes": [ { "code": "Countly.q.push(['change_id', \"myNewId\", true]);", "language": "javascript", "name": "Asynchronous" }, { "code": "Countly.change_id(\"myNewId\", true);", "language": "javascript", "name": "Synchronous" } ] } [/block] [block:api-header] { "type": "basic", "title": "Tracking a session manually" } [/block] ###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. [block:code] { "codes": [ { "code": "Countly.q.push(['begin_session']);", "language": "javascript", "name": "Asynchronous" }, { "code": "Countly.begin_session(noHeartBeat);", "language": "javascript", "name": "Synchronous" } ] } [/block] ###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. [block:code] { "codes": [ { "code": "Countly.q.push(['session_duration', sec]);", "language": "javascript", "name": "Asynchronous" }, { "code": "Countly.session_duration(sec)", "language": "javascript", "name": "Synchronous" } ] } [/block] ###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. [block:code] { "codes": [ { "code": "Countly.q.push(['end_session']);", "language": "javascript", "name": "Asynchronous" }, { "code": "Countly.end_session(sec)", "language": "javascript", "name": "Synchronous" } ] } [/block] [block:api-header] { "type": "basic", "title": "Using Web SDK in Webview" } [/block] 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 [block:code] { "codes": [ { "code": "myWebView.getSettings().setJavaScriptEnabled(true);", "language": "java", "name": "Android" } ] } [/block] 2. Make sure local storage is enabled [block:code] { "codes": [ { "code": "//change the path to where you want to store local storage data\nmyWebView.getSettings().setDomStorageEnabled(true);\nmyWebView.getSettings().setDatabaseEnabled(true);\nif (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {\n myWebView.getSettings().setDatabasePath(\"/data/data/\" + myWebView.getContext().getPackageName() + \"/databases/\");\n}", "language": "java", "name": "Android" } ] } [/block] 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 [block:code] { "codes": [ { "code": "<!--Countly script in webview-->\n<script type='text/javascript'>\n var Countly = Countly || {};\n\tCountly.q = Countly.q || [];\n \n\t//provide countly initialization parameters\n\tCountly.app_key = \"YOUR_APP_KEY\";\n\tCountly.url = \"http://yourdomain.com\"; \n \n //track views or anything else you want to track\n\tCountly.q.push(['track_pageview']);\n \n\t//function to initialize Countly\n\tfunction InitializeCountly(device_id) {\n \n //assign passed device_id\n Countly.device_id = device_id;\n \n //load countly script\n\t\tvar cly = document.createElement('script'); cly.type = 'text/javascript'; \n\t\tcly.async = true;\n\t\t//enter url of script here\n\t\tcly.src = 'https://cdn.jsdelivr.net/countly-sdk-web/latest/countly.min.js';\n\t\tcly.onload = function(){Countly.init()};\n\t\tvar s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(cly, s);\n\t};\n</script>", "language": "html", "name": "WebView" } ] } [/block] Then on native app side all you have to do is to call javascript functions in the Webview and pass device_id to it [block:code] { "codes": [ { "code": "myWebView.loadUrl(\"javascript:InitializeCountly('\"+device_id+\"');\");", "language": "java", "name": "Android" }, { "code": "#import \"CountlyDeviceInfo.h\"\n\nNSString *js = [NSString stringWithFormat: @\"InitializeCountly('%@');\", CountlyDeviceInfo.sharedInstance.deviceID];\n[myWebView stringByEvaluatingJavaScriptFromString:js];", "language": "objectivec", "name": "iOS" } ] } [/block]