CoverStory
LANGUAGES: C# | VB.NET
ASP.NET VERSIONS: 3.5
Time Well Spent
Use ASP.NET AJAX to Track Time Spent on a Page
By Matt Bohn
A frequent requirement for a Web application is for it to collect metrics to determine how users are interacting with it. One solution is to install Web site statistics software that analyzes Web request logs that are available on your Web server. This works well to determine such metrics as page-hit reporting and visitor trends over time. However, one metric that often is not included in traditional request log reporting is the ability to track how long a user stayed on a Web page. By determining how long a user spends on a given page, you can make better decisions to improve your application.
For example, when a user is filling out an online application, you can determine which steps take the longest and focus on improving the usability of those steps. Or you might be running an e-commerce site and you d like to know which product pages users spend the most time on as an indicator of their level of interest. A user might view Product A and immediately leave the page, but when they view Product B they might stay longer and scrutinize all the information on the page to make a purchase decision. If you could track how long they had been on the page, you could offer them the opportunity to chat with a sales agent after they had been on the page for a certain length of time increasing the likelihood of a sale.
The goal of this article is to demonstrate how you can provide more detailed tracking in your Web applications using ASP.NET AJAX. To do this, we ll specifically demonstrate how to track the length of time a user spends on a page as mentioned in the previous scenarios. The techniques illustrated then can be adapted and used to track a variety of user activity metrics.
To track the length of time a user spends on a Web page, you must be able to capture when the page is loaded and when the user leaves the page. The first task is quite simple; a page load can be tracked by logging it in the PageLoad event of the desired page or by using the JavaScript body onload event to make a call to the server using ASP.NET AJAX. However, capturing when the user leaves a page is more complex. Internet Explorer and FireFox support a JavaScript event named onunload that may be included in the page body tag. This event is fired when a user has clicked a link, typed in a new URL, or closed the browser window, which results in the current page being unloaded. Unfortunately, not all browsers support this event. To provide a complete solution, a JavaScript timer can be set up that will ping the server every n seconds with an AJAX request. In conjunction with the onunload event, the page ping provides a solution that can track the time a user spent on a page in most JavaScript and AJAX-capable browsers.
Setting Up the Web Site
We ll begin by creating a new ASP.NET Web site named UserPageTrackingWebSite_VB and add a new master page named MasterPage.master. Once we have the master page added, we ll set up in the project three additional pages (Page1.aspx, Page2.aspx, and Page3.aspx) that use MasterPage.master as their master page. See Figure 1 for the layout of the project at this step. The master page will contain the JavaScript necessary to capture when a user enters and leaves a page. Each page that uses the master page will automatically have these events tracked.
Figure 1: The project layout.
For the sake of this example, we ll handle all events from JavaScript. The next step is to add the JavaScript code to the master page to capture the page load event, capture the page onunload event, and initialize a timer to ping the server every twenty seconds. To do that we ll add a pagePing JavaScript function that is executed by each of these events. It is called when the page loads by using the body onload event and is called on exit using the onunload event. A recurring ping is established using the setTimeout function in our pagePing function to execute pagePing again after twenty seconds has elapsed. Figure 2 illustrates this code in the master page.
<%@ Master Language="VB" AutoEventWireup="true"
CodeFile="MasterPage.master.cs" Inherits="MasterPage" %>
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
onunload="javascript:pagePing(3);">
Figure 2: A recurring ping is established in MasterPage.master.
If you run the code as it appears in Figure 2, you will see an alert box upon page load, an alert every 20 seconds, and an alert if you navigate away from the page. Granted, displaying an alert for each of these events is not the desired result. However, it does illustrate that JavaScript code can be executed for all the events we need to capture, and, if we can execute JavaScript code, we can make an ASP.NET AJAX request to send the data back to the server. You also can see that we are passing a different pingType parameter based on which event is executing the function. This will be used in subsequent steps to tell the Web service which event is occurring.
Setting Up the Database
Before exploring how to make the ASP.NET AJAX request back to the server for the page load, ping, and page exit events, let s create a new database to store the necessary reporting data. Let s create a new SQL 2005 database named UserPageTrackingDB. In this database, create a table named tblPageEvents. This table will store the URL, the session id, the type of the last event that occurred, the timestamp for when the page loaded, the timestamp for the last recurring ping, and the timestamp for page exit. See Figure 3 for the appropriate table schema (note that PageEventID is the primary key and is configured as an auto increment identity column).
Figure 3: The tblPageEvents table in
our SQL 2005 database.
Setting Up the Web Service to Receive Event Data
We now have JavaScript events set up in the master page and a database set up to hold the information about the events. The next step is to create a new Web service to receive event data from the client. To do this, add to the Web site a new Web service named UserPageTrackingService.asmx. This will create a file named UserPageTrackingService.vb in the App_Code folder. In this file, add a Web method named RecordPageActivity, as shown in Figure 4.
Imports System.Web
Imports System.Web.Services
Imports System.Web.Services.Protocols
Imports System.Data.SqlClient
Imports System.Configuration
(ConformsTo:=WsiProfiles.BasicProfile1_1)>
_ DesignerGenerated()> _ Public Class UserPageTrackingService Inherits
System.Web.Services.WebService Public Sub
RecordPageActivity(ByVal Url As String, _ ByVal EventTypeID As
Integer) Dim connStr As String connStr =
ConfigurationManager.ConnectionStrings _ ("PageTrackingConnection").ConnectionString Using conn As New
SqlConnection(connStr) Dim command As
SqlCommand command = _ New
SqlCommand("sproc_AddUpdatePageActivity", _ conn) command.CommandType = _ System.Data.CommandType.StoredProcedure command.Parameters.AddWithValue("@Url", Url) command.Parameters. _ AddWithValue("@LastEventTypeID", EventTypeID) command.Parameters.AddWithValue("@SessionID", _ Session.SessionID) conn.Open() command.ExecuteNonQuery() conn.Close() End Using End Sub End Class Figure 4: Create
the UserPageTrackingService.vb file. You ll notice in Figure 4 that the code calls a stored
procedure named sproc_AddUpdatePageActivity. This procedure has a Url
parameter, a LastEventTypeID parameter, and a SessionID parameter. SessionID is
necessary to determine a series of requests initiated by the same user. LastEventTypeID
tells the stored procedure whether a page load event occurred, a ping occurred,
or a page exit occurred. In this example, an EventTypeID of 1 indicates a page
load, 2 indicates a ping, and 3 indicates a page exit. You ll notice that the
parameter passed to the JavaScript pagePing event in Figure 2 corresponds to
the parameters used by the Web service and stored procedure. To complete the
code to store the data, you ll need to create the stored procedure
sproc_AddUpdatePageActivity, as shown in Figure 5. Note how we record a
timestamp in one of three columns (EnterPage, LastPagePing, or Exit page),
depending on which event type has been passed to the stored procedure. USE [UserPageTrackingDB] GO CREATE PROCEDURE [dbo].[sproc_AddUpdatePageActivity] -- Add the parameters for
the stored procedure here @Url nvarchar(255), @LastEventTypeID int, @SessionID nvarchar(50) AS BEGIN DECLARE @EventID int; SELECT TOP 1
@EventID=PageEventID FROM tblPageEvents WHERE
SessionID=@SessionID AND Url=@Url ORDER BY PageEventID DESC IF (@LastEventTypeID = 1)
BEGIN -- This is the page
entry so record a page entry INSERT INTO
tblPageEvents (Url, LastEventTypeID,
SessionID, EnterPage) VALUES (@Url,
@LastEventTypeID, @SessionID, getdate()); END ELSE IF (@LastEventTypeID
= 2) BEGIN -- This is a page ping
so record the ping by -- updating last record
added for this -- Url/SessionID UPDATE tblPageEvents
SET LastPagePing=getdate(),
LastEventTypeID=2 WHERE
PageEventID=@EventID; END ELSE IF (@LastEventTypeID
= 3) BEGIN -- This is a page exit
so record the exit by -- updating the last
record added for this -- Url/SessionID UPDATE tblPageEvents SET
LeavePage=getdate(), LastEventTypeID=3 WHERE
PageEventID=@EventID; END END Figure 5: Create
the stored procedure sproc_AddUpdatePageActivity. With the Web service now coded to save the information to
the database, we can add code to the master page to call our RecordPageActivity
Web method. To do this we must add a ScriptManager containing a
ServiceReference and set the path of the ServiceReference to the location of
our Web service .asmx file. We then can call the Web service from the pagePing JavaScript
function in our master page. Figure 6 shows what MasterPage.master should
contain after this step (note the changes to pagePing). <%@ Master Language="VB"
CodeFile="MasterPage.master.vb" Inherits="MasterPage" %>
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
onunload="javascript:pagePing(3);">