View the Project on GitHub saleemkce/timeonsite
What is TOS?
Getting Started
Getting current TOS
TOS configuration option
Setting custom data
Unsetting custom data
User sessions **
Extending User Sessions
Saving data to local storage
Real-time example
Additional Features
Backend - Examples
Reporting Dashboard in PHP/NodeJs
Buy Licence/Use it free
Release Notes
TimeOnSite(TOS) tracker is a Javascript snippet that when included in a website will track how much time user spent in the site. The goal of the project is to find time spent by user in individual pages and session as a whole.
Include the timeonsitetracker.min.js in your site, like
<head> <script type="text/javascript"> var Tos; (function(d, s, id, file) { var js, fjs = d.getElementsByTagName(s)[0]; if (d.getElementById(id)) return; js = d.createElement(s); js.id = id; js.onload = function() { var config = {}; if (TimeOnSiteTracker) { Tos = new TimeOnSiteTracker(config); } }; js.src = file;fjs.parentNode.insertBefore(js, fjs); } (document, 'script', 'TimeOnSiteTracker', 'timeonsitetracker.min.js')); </script> </head>
Then, open browser console/developer console; you will see TimeOnSiteTracker imprint. Just type following line to see current "Time on page" and related data.
console.log(Tos.getTimeOnPage());
If you could see TOS data, hooray! your TOS tracking is successful, that means, the TimeOnSiteTracker is correctly integrated in your site!
Note: Time on page and Time on site are captured in milliseconds (Javascript's Date function) by default.
You could call Tos anytime in the page by simple accessing Tos.getTimeOnPage()
API in browser console provided that you initialized TOS correctly.
// It's assumed you correctly initialized Tos in the page as, var Tos = new TimeOnSite(); Tos.getTimeOnPage(); //Response -> { TOSId: 1129620185532, TOSSessionKey: "14802525481391382263", TOSUserId: "anonymous", title: "Test application - TimeOnSiteTracker", URL: "http://tos-localdata.chennai/home.php" entryTime: "2016-11-27 13:15:48.663", currentTime: "2016-11-27 13:17:31.663", timeOnPage: 103, timeOnSite: 0, timeOnPageTrackedBy: "second", timeOnPageByDuration: "0d 00h 01m 43s", timeOnSiteByDuration: "0d 00h 00m 00s", trackingType: "tos", }
Parameter | Type | Description |
---|---|---|
TOSId | Integer | unique TOS id that is created when Tos.getTimeOnPage() is called |
TOSSessionKey | String | It tracks particular user session. If user clicks 5 different pages in the same site, then all TOSSessionKey will refer to same session |
TOSUserId | String | It is usually "anonymous" unless you modify it by calling Tos.startSession('username'); immediately after user authentication |
title | String | Title of the web page |
URL | String | Page URL |
entryTime | String | The time when user enters the site and TOS Tracker is initialized |
timeOnPage | Integer | Time spent by user in current page |
timeOnPageByDuration | String | Time duration in more readable format |
timeOnPageTrackedBy | String | It denotes whether page is being tracked by "second" or "millisecond" |
timeOnSite | Integer | Time spent by user in the session(sum of TimeOnPage(TOP)) |
timeOnSiteByDuration | String | Time duration in more readable format (sum of TimeOnPage(TOP)) |
trackingType | String | It can be "tos" or "activity" which refers to either time on site tracking or activity tracking |
When initializing timeonsitetracker.js in your site, the first parameter requires a "config" parameter which is optional and it controls the way TOS data is tracked. For example, look at the following option.
var config = { // track page by seconds. Default tracking is by milliseconds trackBy: 'seconds', // pages to blacklist; give URLs in array eg. ['URL1', 'URL2', 'URL3'] blacklistUrl: ['http://tos-localdata.chennai/blog/id/1'], //this parameter helps track pageviews for single-page apps that use hash-based URL routing trackHistoryChange: true, //this parameter helps track user's TOS data separately for two different sub-domins of a site or a domain and its sub-domain. It works just like normal cookie for domain and path but is associated with TOS Tracking specifically TOSCookie: { path: '/', domain: 'blog.example.com' } //save to local storage. If you give callback along with this option, callback will take precedence request: { url: 'http://localhost:4500/tos', //your endpoint URL to which data would be sent via POST method in API call headers: [ {'App-userID': 234982348923}, //optional headers if any like authentication, token etc. {'App-session': 'x2872034ULT'} //optional headers if any ] }, // if you give callback, it becomes real-time tracking because data is sent to server immediately on page close callback: function(data) { window.open('http://www.example.com', 'hi', 'height=200,width=200'); }}; // this is just for illustration, give only the options that you need.
To capture all TOS data in seconds format instead of milliseconds, give the "trackBy" option as given below:
// use call back data "time on site" data var config = { trackBy: 'seconds', callback: function(data) { // if you give callback, it becomes real-time tracking console.log(data); // give your end-point URL to save data to DB }};
You may want to block specifc page from getting tracked. This is possible in normal web sites (pages loaded with full rendering) but not in single-page apps. To make use of this option,
you need to give "blacklistUrl" parameter,
var config = { trackBy: 'seconds', blacklistUrl: ['http://tos-localdata.chennai/home.php'], // pages to blacklist; give //URLs in arrary eg. ['URL1', 'URL2', 'URL3'] callback: function(data) { // if you give callback, it becomes real-time tracking console.log(data); }};
This option is very useful in debugging TOS Tracker data. It also helps to point out any
incorrect input you might give while initializing timeonsitetracker.js. These are all visible in browser console window (Open browser console and look at real-time TOS Tracker data, you may see a lot of data in browser console when this option is enabled). Also this setting may be useful only for development or test environments and not recommended for production. This is enabled by "developerMode" as given below.
var config = { trackBy: 'seconds', developerMode: true, request: { // presence of request object denotes that data is to be saved in local storage and processed on subsequent page access url: 'http://localhost:4500/tos', headers: [ // optional headers if any ] } };
This is a very important setting when working with domains and sub-domains for TOS Tracking. This cookie is used to determine if current TOS tracking applies to whole domain or a sub domain in the given site. If you are going to track entire site without differentiating domain and sub domain, you may leave this option. For this, you need to provide "TOSCookie" in config object as given below so that tracking works as per your needs,
//Setting custom data for TOS tracking var config = { trackBy: 'seconds', TOSCookie: { path: '/', domain: 'example.com' } };
In the above line, TOS Tracker is going to track all domain and sub-domain as one thing. For example, consider TOS Tracking is implemented in example.com. If the above cookie is set for path => '/' and domain => 'example.com' in example.com, then TOS tracking session ID/key is same for both blog.example.com and about.example.com. But, blog.example.com is actually different from about.example.com, each serves its own purpose and their usage should be treated differently. Since we gave domain as "example.com", TOS timing parameter gets mingled if a user tries to access blog.example.com and about.example.com one by one at the same time. To avoid data mixing and keep each thing different, domain parameter helps us do that
//Setting custom data for TOS tracking //Example 1: setting for blog.exmaple.com var config = { trackBy: 'seconds', TOSCookie: { path: '/', domain: 'blog.example.com' } }; //Example 2: setting for about.exmaple.com var config = { trackBy: 'seconds', TOSCookie: { path: '/', domain: 'about.example.com' } };
When the setting is changed as above, user simultaneously accessing 'blog' and 'about' sub-domains is protected from mixing TOS session data of both sub domains. To describe, you will find two session IDs created for accessing each sub-domain and each session ID uniquely identifies time on site of sub-domains separately. It works just like domain cookies in sites but for tracking TOS.
TimeOnSite tracker captures TOS information for normal web pages when page is closed, reloaded or navigated to another page using beforeunload browser API. This is not the case with single-page apps where navigation to different pages does not trigger beforeunload window event and in this case TOS is not tracked. To overcome the problem, fortunately, browsers support window.history API which gets called when page navigation occurs in single-page apps. For example, to navigate from example.com/#home -> example.com/#contact page in single-page app. When you go from "home" page to "contact" page, history API helps track the page navigation correctly. To make use of it, give config trackHistoryChange as,
var config = { trackBy: 'seconds', trackHistoryChange: true, callback: function(data) { // if you give callback, it becomes real-time tracking console.log(data); }};Remember that failing to configure this trackHistoryChange setting may not identify different pages correctly in tracked TOS data.
When implementing TOS in your website or application, you may want to track additional details along with TOS data. For example, you see "timeOnPage", "URL", "title" etc. in the object returned by TOS on page close. What if you want to set userId, userName, userType or userActivity? This is where Tos.setCustomData()
API comes into action. It helps you track additional data in your webpage. Look at the example given below,
//Setting custom data for TOS tracking var custom = { userId: 'u23842238924', userName: 'Khan', actions: ['view', 'audio-start', 'read'] }; Tos.setCustomData(custom); //before the page is closed, this data is appended to TOS result.
Now if you call Tos.getTimeOnPage()
from browser console, you could see this custom data along with usual TOS data
//Response -> { TOSId: 1129620185532, TOSSessionKey: "14802525481391382263", TOSUserId: "anonymous", title: "Test application - TimeOnSiteTracker", URL: "http://tos-localdata.chennai/home.php" entryTime: "2016-11-27 13:15:48.136", timeOnPage: 103, timeOnSite: 0, timeOnPageTrackedBy: "second", timeOnPageByDuration: "0d 00h 01m 43s", timeOnSiteByDuration: "0d 00h 00m 00s", trackingType: "tos", //custom data added to TOS response. It would be saved to DB on page close. Wow! userId: 'u23842238924', userName: 'Khan', actions: ['view', 'audio-start', 'read'] }
To remove the custom data already set, simply call Tos.unsetCustomData()
API and you are done. It will only remove any custom data set by you.
You have learnt a lot about TimeOnSiteTracker and its configuration options. Now, it's time to set user ID to track and understand the behaviour of authenticated users in your application. For this, you may use Tos.startSession()
API as given in example below. Moreover, this is optional setting but highly recommended in case your application makes use of authentication/login routine. If not set, all TOS tracking will be tracked as "anonymous" users in your application.
// when user is logged into your site, call startSession. Tos.startSession('u2439ULasxv'); //"u2439ULasxv" is user id as available in your application //when user logs out of your application, call endSession. Tos.endSession();
Remember, you may call Tos.startSession()
API only when user logs into your application and call Tos.endSession()
only when user logs out. Calling Tos.endSession()
too many times or unnecessarily may create inconsistent identity data in your DB. Failing to call Tos.endSession()
, when user logs out in your application, may result in loss of that session data.
In section "User sessions" above, we saw how to capture TOS data for authenticated users in your application by calling Tos.startSession('testUser1')
. Once started, this session information is stored in cookie and stays there for 1 day until Tos.endSession() is called. When Tos.endSession() is called, this authenticated user session is destroyed from cookie. For some applications, they may set smaller lifetime for authenticated sessions. TimeOnSite tracker needs to be in sync with such applications for capturing TOS data of authenticated users. In TimeOnSite tracker, fortunately, there is a way to modify default lifetime of cookies for authenticated users. This is done by calling Tos.extendSession()
methed after starting TOS session.
// when user is logged into your site, call startSession. Tos.startSession('testUserId1'); //"testUserId1" stays in cookie for next 1 day but your application preference is to auto-destroy authenticated user session every one hour. In this case, you are forced to auto-destory TOS authenticated session at the same time. //Just call extend session API. Tos.extendSession(3600); // This modifies current authenticated session lifetime to 1 hour instead of default 1 day. // or give any value Tos.extendSession(900); // This modifies current authenticated session lifetime to 15 minutes instead of default 1 day. // or give even bigger value Tos.extendSession(604800); // This modifies current authenticated session lifetime to 7 days (1 week) instead of default 1 day.
The method Tos.extendSession(3600)
accepts first parameter as time period in seconds. It is of type number. In this snippet, 3600 seconds which is 1 hour. Also be aware that the value given to this API modifies the lifetime of cookie instead of adding to existing default 1 day lifetime of cookie. If you give incorrect value or very less time period like 10 seconds, it may not work correctly. This API is applicable only for authenticated user sessions.
When you give callback TOS option, TimeOnSiteTracker tries to send data immediately on page/tab close. Since it makes a HTTP request at this point and it is synchronous, it slows down the tab close action otherwise the navigation would be a bit slower. But, this is real-time tracking. On the other hand, if you give local storage option, data is saved to local storage and processed later. This won't be real-time but it doesn't affect user's site navigation.
// save to local storage; don't give callback when saving to local storage var config = { trackBy: 'seconds', request: { // presence of request object denotes that data is to be saved in local storage and processed on subsequent page access url: 'http://localhost:4500/tos', //your endpoint URL to which data would be sent via POST method in API call headers: [ {'App-userID': 234982348923}, //optional headers if any like authentication, token etc. {'App-session': 'x2872034ULT'} //optional headers if any ] }};
// save with sendBeacon or XMLHttpRequest var config = { trackBy: 'seconds', callback: function(data) { console.log(data); // give your endpoint URL/ server-side URL that is going to handle your TOS data which is of POST method. Eg. PHP, nodejs or python URL which saves this data to your DB var endPointUrl = 'http://localhost:4500/tos'; // replace with your endpoint URL if (data && data.trackingType) { if (data.trackingType == 'tos') { if (Tos.verifyData(data) != 'valid') { console.log('Data abolished!'); return; } } // makes use of sendBeacon API in your browser. if (navigator && typeof navigator.sendBeacon === 'function') { var blob = new Blob([JSON.stringify(data)], {type : 'application/json'}); navigator.sendBeacon(endPointUrl, blob); } /*else { // XMLHttpRequest begins.. var url = endPointUrl, params = JSON.stringify(data), xhr; xhr = new XMLHttpRequest(); xhr.open('POST', url, false); //synchronous call; changing this to true will make it asynchronous request and data may not be saved in your DB. //Send the proper header information along with the request xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8'); // IOS/Safari ajax POST issue fixer without no-cache header xhr.setRequestHeader('cache-control', 'no-cache'); xhr.onreadystatechange = function() {//Call a function when the state changes. if (xhr.readyState == 4 && xhr.status == 200) { if (xhr.responseText == 'success') { console.log('Data saved successfully!'); // Warning: But you should not do more operations here since it will //block user from closing the application or slow down site navigation } } } xhr.send(params); // XMLHttpRequest ends.. }*/ } }};
if (data && data.trackingType) {we check if there is data from TimeOnSiteTracker.js during page close.
if (navigator && typeof navigator.sendBeacon === 'function') {we check if browser supports sendBeacon() API which could send data asynchronously and safely to server without blocking user interface. If this API is supported by browser, we make use of it.
xhr.open('POST', url, false); //synchronous call; changing this to true will make it asynchronous request and data may not be saved in your DB.
In sendBeacon's else loop, you could see this. If sendBeacon() API is not supported by browser, we use normal XMLHTTPRequest to send data synchronously to server. Note the 3rd parameter "false" which is responsible for sending data to server before page gets closed.
TimeOnSiteTracker also helps you track a particular interaction or activity in the site. The goal of this feature is to capture time taken by the user to complete the activity. You have to manually trigger Tos.startActivity()
and
Tos.endActivity()
APIs to capture start and end time of activity. starActivity() and endActivity() API methods accept optional first parameter as Javascript object through which you can set custom data.
// Usual tracker initialization at header. Only once! var config = { trackBy: 'seconds' }}; // After initializing the TimeOnSiteTracker on page load, call startActivity() as Tos.startActivity(); // this will start tracking the activity // . // . // . // after a while, Tos.endActivity(); // calling .endActivity() will give back response Gives response as, { TOSId: 585872449448, TOSSessionKey: "14802525481391382263", TOSUserId: "anonymous", title: "Test application - TimeOnSiteTracker", URL: "http://tos-localdata.chennai/home.php", activityStart: "2016-11-27 13:20:46.707", activityEnd: "2016-11-27 13:20:50.213", timeTaken:4, timeTakenByDuration: "0d 00h 00m 04s" timeTakenTrackedBy: "second", trackingType: "activity", } // Another scenario with optional first parameter Tos.startActivity({name: 'foo', city: 'bar'}); // this will start activity tracking with custom data setIt has different parameters in response like "activityStart", "activityEnd", "timeTaken" etc. It's independent of normal TOS tracking which starts at page load and ends at page close.
var manualProcess = true; var activityData = Tos.endActivity({}, manualProcess); /** * Notice variable "manualProcess" which is boolean and is set to true. This indicates that data will not be handled by callback function or local storage. Instead, activityData is simply retured to variable for you to do anything manually. * You may add any additional data to this "activityData" object and save it to database as you wish. * * activityData.userPreferences = ['social', 'journal', 'history']; * activityData.userId = 2427032032u; * * Now save "activityData" object to database for understanding user preferences. */
Parameter | Type | Description |
---|---|---|
TOSId | Integer | unique TOS id that is created when Tos.getTimeOnPage() is called |
TOSSessionKey | String | It tracks particular user session. If user clicks 5 different pages in the same site, then all TOSSessionKey will refer to same session |
TOSUserId | String | It is usually "anonymous" unless you modify it by calling Tos.startSession('username'); immediately after user authentication |
title | String | Title of the web page |
URL | String | Page URL |
timeTaken | Integer | The time duration it takes for user to complete the activity/interaction |
timeTakenByDuration | String | Activity duration in more readable format |
timeTakenTrackedBy | String | It denotes whether page is being tracked by "second" or "millisecond" |
activityStart | String | The time when user starts the activity |
activityEnd | String | The time when user finishes the activity |
trackingType | String | It can be "tos" or "activity" which refers to either time on site tracking or activity tracking |
Developed with love for web & analytics at Chennai, remember Marina? All praise be to Almighty God.
TimeonsiteTracker.js, the commercial software.