Tracking visitors behaviour in your web application

ASP.NET, PHP, Tutorials

So you want to know how much time users spend on any specific page of your web application? This article explains how to log what pages your users visit and how much time they spend on each page. This kind of data can provide valuable insight into what forms of your application are too complicated and need to be split into several smaller forms. Or if they keep coming back to the welcome page this may mean your navigation inside the app can be improved.


1. Create log table

The following SQL script creates the log table in the database. The syntax is for MySQL, you can create a similar table in any other database manually, just make sure that field names and datatypes stay the same.

CREATE TABLE `timetracker` (
  `trackerId` int(11) NOT NULL AUTO_INCREMENT,
  `pagename` varchar(250)  DEFAULT NULL, /* page URL */
  `timeon` datetime DEFAULT NULL, /* when user entered the page */
  `timeoff` datetime DEFAULT NULL, /* when user left the page */
  `userID` varchar(100) DEFAULT NULL, /* username */
  `recordID` varchar(100) DEFAULT NULL, /* in the case of edit/view pages this field will store the ID of the record */
  PRIMARY KEY (`trackerId`)
)

A few notes here:

Note 1: Login is not required. If your project doesn't use login, 'userID' field will be empty.

Note 2: if 'timeoff' field is empty that means user spent less than five seconds on the page.

Note 3: it makes sense to add 'timetracker' table to the project as well so you can test this functionality. If you do so, set 'View as' time of timeon/timeoff fields to 'Datetime'.

2. Javascript code

The following Javascript code needs to be added under Event Editor -> custom_functions.js

$("document").ready(function() {
    Runner.customEvents = [];
    // every notifyInterval seconds we execute an AJAX requests that tells the server that user is still ont he page
    var notifyInterval = 5;

    // this function is executed on every page load, here we tell the server what page the user currently on

    function setPageTimer(pageObj) {
	// ajax- parameters with the page URL
        var notify_params = { pageOpen: 1, pageName: Runner.pages.getUrl(pageObj.shortTName,pageObj.pageType) };
	// if this is an Edit/View page we also pass an ID of the record
        if (pageObj.pageType === "edit" || pageObj.pageType === "view") notify_params.recordID = pageObj.keys[0];
	// we send AJAX request and get back trackerId value of the current log table recod
        $.get("", notify_params, function(TrackerID) {
	// send AJAX request with the current notifyInterval value, that tells the server the user is still on the page
            interval = setInterval(function() {
                $.get("", { TrackerID: TrackerID });
            }, notifyInterval * 1000);
        });
    }

    var originalInit = Runner.pages.RunnerPage.prototype.init;
  
    Runner.pages.RunnerPage.prototype.init = function() {
        var pageObj = this;
        var isTab = typeof this.tabControl !== "undefined";
	// check if the current page a details tab
        if (isTab) {

	if (!Runner.customEvents.includes(this.tName + "_" + this.pageType)) {
            Runner.customEvents.push(this.tName + "_" + this.pageType);
            pageObj.on("afterPageReady", function() {
                // when tab is closed we clear the interval counter
		pageObj.tabControl.off("hide.bs.tab").on("hide.bs.tab", function(e) {
                    clearInterval(interval);
                });
		// when details tab is open we start the counter
                pageObj.tabControl.off("show.bs.tab").on("show.bs.tab", function(e) {
                    var activeTab = $(e.target);
                    var panelContent = activeTab.parents("ul").next();
                    var activePanel = panelContent.find(".tab-pane.active");

                    setPageTimer(Runner.pages.PageManager.getById(activePanel.find(".r-form").attr("data-pageid")));

                });
            });
				}

        }

        if (!isTab || (isTab && this.$panel.parents(".tab-pane").hasClass("active"))) {
            setPageTimer(pageObj);
        }

        originalInit.call(this);
    }
});

3. Server-side code (PHP and C#)

The following code goes to the AfterAppInit event.

PHP:

$currentDateTimeForDb = localdatetime2db( runner_date_format("m-d-y H:i:s") );
// receiving AJAX request with the new page URL
// in timetracker table we create a new record 
// and return the TrackerID value of the new record
if( postvalue("pageOpen") != false ){
		$data = array();
		$data["pagename"] = postvalue("pageName");
		$data["timeon"] = $currentDateTimeForDb;
		$data["userID"] =  Security::getUserName();
		if(postvalue("recordID") != false){
			$data["recordID"] = postvalue("recordID");
		}
		DB::Insert("timetracker", $data);
		//return TrackerID
		echo DB::LastId();
		exit();

}
// receiving AJAX request that tell us we are still on the same pageпродолжается
// we just update the value of timeoff field for the current TrackerID
if( postvalue("TrackerID") !=false ){
	$now_datetime = $currentDateTimeForDb;
	DB::Update("timetracker",array("timeoff"=> $now_datetime ),array("trackerId" => postvalue("TrackerID") ));
	exit();
}

C#:

dynamic currentDateTimeForDb = null;
currentDateTimeForDb = XVar.Clone(CommonFunctions.localdatetime2db((XVar)(MVCFunctions.runner_date_format(new XVar("m-d-y H:i:s")))));
if(MVCFunctions.postvalue(new XVar("pageOpen")) != false)
{
	data = XVar.Clone(XVar.Array());
	data.InitAndSetArrayItem(MVCFunctions.postvalue(new XVar("pageName")), "pagename");
	data.InitAndSetArrayItem(currentDateTimeForDb, "timeon");
	data.InitAndSetArrayItem(Security.getUserName(), "userID");
	if(MVCFunctions.postvalue(new XVar("recordID")) != false)
	{
		data.InitAndSetArrayItem(MVCFunctions.postvalue(new XVar("recordID")), "recordID");
	}
	DB.Insert(new XVar("timetracker"), (XVar)(data));
	MVCFunctions.Echo(DB.LastId());
	MVCFunctions.ob_flush();
	HttpContext.Current.Response.End();
	throw new RunnerInlineOutputException();
}
if(MVCFunctions.postvalue(new XVar("TrackerID")) != false)
{
	dynamic now_datetime = null;
	now_datetime = XVar.Clone(currentDateTimeForDb);
	DB.Update(new XVar("timetracker"), (XVar)(new XVar("timeoff", now_datetime)), (XVar)(new XVar("trackerId", MVCFunctions.postvalue(new XVar("TrackerID")))));
	MVCFunctions.ob_flush();
	HttpContext.Current.Response.End();
	throw new RunnerInlineOutputException();
}
return null;

3 thoughts on “Tracking visitors behaviour in your web application

Leave a Reply

Your email address will not be published. Required fields are marked *