Track Client-side Events in Sitecore MVC

footprints in snow

Tracking events triggered on your site is obviously of vital importance to measure your visitors’ behaviour and level of engagement. Sitecore does a good job of tracking events associated to a page that are triggered upon page visit – but in reality, we are more concerned about tracking client-side events especially since almost everything happens on the client-side these days due to the emergence of frameworks like Angular and Ember. Though Sitecore is somewhat limited in this aspect we can definitely utilize the very rich Sitecore Analytics API to accomplish this feat.

The Sitecore Analytics API works only if there’s an active session. The good news is you can create your own non-Sitecore MVC controllers and use them like REST endpoints, and you can expect that they will be executed in the same session as your Sitecore pages. With that in mind there’s no stopping you from registering your Sitecore page events from the client-side, and the only thing you need to know now is how to register page events programmatically.

The Controller code

Here’s a very basic controller action to register the page event:

[DisableTracking]
public class AnalyticsController : Controller
{
    [HttpPost]
    public ActionResult TrackEvent(string name, string data, string text)
    {
        var pageEventData = new PageEventData(name) { Data = data, Text = text };
        var interaction = Tracker.Current.Session.Interaction;
        var localPath = Request.UrlReferrer?.LocalPath;
        var page = interaction.GetPages().LastOrDefault(n => n.Url.Path == localPath);

        page?.Register(pageEventData);
        interaction.AcceptModifications();
            
        return new HttpStatusCodeResult(HttpStatusCode.OK);
    }
}

FYI: You may want to check if the page event has actually been registered and return an appropriate status code if it’s not. After the page.Register call you can check the last event in page.PageEvents to see if it maches the PageEventData.

You may have also noticed that I used the UrlReferrer’s local-path to determine the current executing page. It’s because an MVC controller action is treated as a page, therefore, you’re considered to be in the TrackEvent page when executing the path. And since it is a page you may want to disable tracking on it, hence, I added an Action Filter called ‘DisableTracking’ using the code below:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public sealed class DisableTrackingAttribute: ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        Sitecore.Analytics.Tracker.Current.CurrentPage.Cancel();

        base.OnActionExecuting(filterContext);
    }
}

Registering the Route

Assuming you’re already aware that by default attribute routing does not work in Sitecore 8, and that you’ve already nailed down registering MVC routes in the ‘Initialize’ pipeline, this is how you can register your action route:

private static void RegisterAnalyticsRoutes(RouteCollection routes)
{
    routes.MapRoute(
        name: "TrackEvent",
        url: "analytics/trackevent",
        defaults: new { controller = "Analytics", action = "TrackEvent" }
    );
}

The client-side

Before we can call the page-event on the client-side we need to create a client-side function to send the tracking information to our Controller action:

function trackClickEvent() {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (xhttp.status == 200) {
      // perform callback action here
    }
  };
  xhttp.open("POST", "/analytics/trackevent", true);
  xhttp.setRequestHeader("Content-type", "application/json");

  var obj = JSON.parse(this.getAttribute("data-tracking"));
  var json = JSON.stringify(obj);
  xhttp.send(json);
}

For example, this link is our trackable element:

<a href="#" data-tracking="{"name":"Link Clicked","data":"some data","text":"some text"}">Click this link</a>

Now we just need to attach the trackClickEvent function to our trackable elements:

var elems = document.querySelectorAll('[data-tracking]');

// for the sake of brevity let's just use a for-loop
for(var i = 0; i < elems.length; i++) {
  elems[i].onclick = trackEvent;
}

Feel free to comment about suggestions to improve this approach. Happy coding!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s