Sunday, May 15, 2016

3-Step Guide: How to trigger an xDB goal using jQuery AJAX with Sitecore MVC

Standard

Background

After cruising around the web looking for some code to use to trigger a goal using jQuery AJAX, I discovered that there weren't really any easy to understand, end-to-end, current examples of how to do this using Sitecore MVC.

So, I decided to write up a quick post to demonstrate how to do this in 3 easy steps.


Step 1 - Create MVC Controller

The first step is to create an MVC Controller with an action that you will use to trigger the goal:

 using System;  
 using System.Linq;  
 using System.Web.Mvc;  
   
 using Sitecore.Analytics;  
 using Sitecore.Analytics.Data.Items;  
 using Sitecore.Mvc.Controllers;  
   
 namespace MyNamespace.Controllers  
 {  
   public class AnalyticsController : SitecoreController  
   {  
     private const string DefaultGoalLocation = "/sitecore/system/Marketing Control Panel/Goals";  
   
     [HttpPost]  
     public ActionResult TriggerGoal(string goal)  
     {  
       if (!Tracker.IsActive || Tracker.Current == null)  
       {  
         Tracker.StartTracking();  
       }  
   
       if (Tracker.Current == null)  
       {    
         return Json(new { Success = false, Error = "Can't activate tracker" });  
       }  
   
       if (string.IsNullOrEmpty(goal))  
       {  
         return Json(new { Success = false, Error = "Goal not set" });  
       }  
   
       var goalRootItem = Sitecore.Context.Database.GetItem(DefaultGoalLocation);  
       var goalItem = goalRootItem.Axes.GetDescendants().FirstOrDefault(x => x.Name.Equals(goal, StringComparison.InvariantCultureIgnoreCase));  
   
       if (goalItem == null)  
       {  
         return Json(new { Success = false, Error = "Goal not found" });  
       }  
   
       var page = Tracker.Current.Session.Interaction.PreviousPage;  
       if (page == null)  
       {  
         return Json(new { Success = false, Error = "Page is null" });  
       }  
   
       var registerTheGoal = new PageEventItem(goalItem);  
       var eventData = page.Register(registerTheGoal);  
       eventData.Data = goalItem["Description"];  
       eventData.ItemId = goalItem.ID.Guid;  
       eventData.DataKey = goalItem.Paths.Path;  
       Tracker.Current.Interaction.AcceptModifications();  
   
       Tracker.Current.CurrentPage.Cancel();   
   
       return Json(new { Success = true });  
     }  
   }  
 }  

Step 2 - Register a custom MVC route

The next step is to create a custom processor for the initialize pipeline and define custom route in the Process method similar to the following:

 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Web;  
 using System.Web.Mvc;  
 using System.Web.Routing;  
 using System.Web.UI.WebControls;

 using Sitecore.Pipelines;  
   
 namespace MyNamespace  
 {  
  public class RegisterCustomRoute  
  {  
   public virtual void Process(PipelineArgs args)  
   {  
    Register();  
   }  
   
   public static void Register()  
   {  
    RouteTable.Routes.MapRoute("CustomRoute", "MyCustomRoute/{controller}/{action}/{id}");  
   }  
   
  }  
 }  

Add this processor to the initialize pipeline right before the Sitecore InitializeRoutes processor. You can do this with the help of the patch configuration file in the following way:

 <?xml version="1.0" encoding="utf-8"?>  
 <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">  
  <sitecore>  
   <pipelines>  
    <initialize>  
     <processor type="MyNamespace.RegisterCustomRoute, MyAssembly"/>  
    </initialize>‌  
   </pipelines>  
  </sitecore>  
 </configuration>  

Step 3 - Trigger using jQuery

Finally, trigger the goal by name using a few lines of jQuery:

 $.post("/MyCustomRoute/Analytics/TriggerGoal?goal=tweet" ,function(data){  
      //Do something with data object  
 });  

5 comments:

  1. Appreciate the post - saved me a lot of time. Thanks Martin!

    ReplyDelete
  2. Only recommendation: Specify "goal" using jQuery's second parameter (post data) instead of via GET value. Otherwise, be sure to `encodeURIComponent` the goal name when specifying it in the POST URL. e.g.

    Modifying your version:
    $.post('/MyCustomRoute/Analytics/TriggerGoal?goal=' + encodeURIComponent('tweet'), function(){ ... });

    Leveraging jQuery and POSTing like a POST.
    $.post('/MyCustomRoute/Analytics/TriggerGoal',{goal:'tweet'},function(){ ... });

    Otherwise very helpful!

    ~Brad

    ReplyDelete
  3. Hey martin, Thank you for this. Why do you need " Tracker.Current.CurrentPage.Cancel();" at the end of the code?

    ReplyDelete
  4. Hi Jose,

    If you don't cancel, you would end up seeing the path of the controller action in analytics , which is obviously undesirable.

    Cheers!

    ReplyDelete