Sitecore Query String Event Tracking
One common usage of tracking is to track query strings. It is not an uncommon task to learn more about a user's visit based on what their query string values are. These are a common component in driving things like search or walking through a product catalog. And if you have ever worked with Google analytics you know there is specific query strings that can tag campaigns. Now if you know specific pages that a specific type of query string format will land on you can write specific page event. This is covered in my previous blog on Sitecore Code Base Page Event Tracking . A single scenario like looking for the "searchStr" key on a search page would be a good example and would give you some data on what kind of things your visitors are searching for. You could even go as far as exposing this at a higher level and attaching to your main layout. But I wanted to explore beyond this and see how I could create a catch all for any query string that hits the site. And to not just limit this to Sitecore specific page calls but also to explore scenarios where calls may occur against web services. First I looked at seeing if I could attach this to the pipelines httpRequestBegin and httpRequestEnd but found that I could not expose the session from here. So I looked higher up and attached it to < />
public class AnalyticsHttpModule : IHttpModule { public AnalyticsHttpModule() { } public String ModuleName { get { return "AnalyticsHttpModule"; } } public void Init(HttpApplication application) { application.PostAcquireRequestState += RequestHandler; } public void RequestHandler(object sender, EventArgs e) { var app = (HttpApplication)sender; // confirms a proper session is set. if (app.Context.Handler is IRequiresSessionState) { if (app.Request.Cookies["SC_ANALYTICS_SESSION_COOKIE"] != null) { // if cookie is not set, any tracker actions will append visit to a previous visit foreach (String key in app.Request.QueryString.AllKeys) { Analytics.RegisterPageEvent("Track Query String", String.Format("Track Query String = key : {0}, value : {1} ", key, app.Request.QueryString[key]), app.Request.QueryString[key], key); } } } } public void Dispose() { } }
First and foremost, make sure you inherit from the IHttpModule. Then inside my RequestHandler the first thing you want to do is check to confirm that you have a valid session. Secondly you have to check for an analytic session cookie. Unfortunately the draw back to this approach is that if this happens on the first page the analytics session is not there yet and either an error will occur or analytics will fallback to the previous user session and in affect attach the entire session here going forward. Finally we loop through the query string key / value pairs and register our event. The RegisterPageEvent method is covered on my previous post. The above will cover all scenarios where a query string is used during a visitors session except the first page. To fix this problem I had to make an assumption that initial page visit would always be a Sitecore rendered page. This was acceptable as I could not think of a scenario where it would not be. Generally speaking you go to some basic starting point or have some sort of page render before a call to a web service would occur. Even if this happens on the first page load, you should be in good shape at this point because analytics has fully run through once and created this session for the visitor. So along this train of thought I added the following code to my main layout:
if (Tracker.Visitor.CurrentVisit.CurrentPage.VisitPageIndex == 1) { foreach (String key in Request.QueryString.AllKeys) { Analytics.RegisterPageEvent("Track Query String", String.Format("Track Query String = key : {0}, value : {1} ", key, Request.QueryString[key]), Request.QueryString[key], key); } }
The first thing this looks for is to check and see if the current visit's current page is first in our index. Then we look for all the query string keys and registers our events. This allows us to run this logic only on the first page hit and every call after is handled by the class we attached to the