Sitecore campaigns and UTM tracking unified

Sitecore and UTM 

A lot of blogs have been written about Sitecore vs Google Analytics and how they can be complimentary.
In many of the implementations I have seen, marketers use these tools side by side. 
As marketers seem so fond of Google Analytics and have a hard time parting with it to only use Sitecore, I figured, why not make them work at the same time.
Marketers seem to be more familiar with setting up campaigns using UTM than setting them up with custom parameters for Sitecore campaigns, so why not make Sitecore work with these UTM parameters as well. 
So what I did is make it configurable in Sitecore to hookup UTM parameters to Sitecore campaigns. This blog shows how I did that.

Setting up your templates

I started by defining a template where you can tie these together.
  • Field1: UTM Source key
    • Single-line text to copy your UTM source key into
  • Field2: Linked Campaign
    • A droptree field with a query, something like this: query:/sitecore/system/Marketing Control Panel/Campaigns/CustomerFolder//*[@@templatename = 'Campaign']

Custom processor to enroll into your campaigns

Then I made a custom processor to catch the incoming 'utm_source' etc. parameters to be used to enroll in the Sitecore campaign that you can create to hook it up to.
This processor iterates through all configured UTM/campaign configurations made and sees if a matching campaign is found and if so registers the campaign as an interaction.


 
    /// 
    /// This processor evaluates presence of utm_source in querystring parameters and if present enrolls current contact in corresponding Sitecore campaign (if any is configured)
    /// 
    public class UtmProcessor : ProcessQueryStringCampaign
    {
        public override void Process(StartTrackingArgs args)
        {
            base.Process(args);

            if (args.HttpContext.Request.Url.Query.Contains("utm_source"))
            {
                var campaignItem = AnalyticsHelper.GetUtmCampaign(args.HttpContext.Request);
                if (campaignItem == null)
                {
                    Log.Info("Campaign not found for utm_source: " + args.HttpContext.Request.Url.Query, typeof(ProcessQueryStringCampaign));
                    return;
                }

                System.Guid? campaignId = campaignItem.ID.Guid;
                Tracker.Current.CurrentPage.TriggerCampaign(campaignItem);
                System.Guid? currentCampaignId = Tracker.Current.Session.Interaction.CampaignId;
                if (campaignId != Tracker.Current.Session.Interaction.CampaignId)
                {
                    TrackerEvents.OnCurrentPageCancelled += delegate (object sender, System.EventArgs eArgs)
                    {
                        Tracker.Current.Session.Interaction.CampaignId = currentCampaignId;
                    };
                }
            }
        }
    }



        /// <summary>
        /// Based on http request, check incoming utm_source querystring and enroll into Sitecore campaign if such is configured for utm source.
        /// </summary>
        /// <param name="request">Incoming http request</param>
        /// <returns>Campaign item to </returns>
        public static CampaignItem GetUtmCampaign(HttpRequestBase request)
        {
            if (request == null || string.IsNullOrEmpty(request.QueryString["utm_source"]))
            {
                return null;
            }

            var campaignsFolder = ContentHelper.GetConfigurationItemByBaseTemplate(SitecoreConstants.UTMCampaignsFolder.TemplateName);

            if (campaignsFolder == null || campaignsFolder.Children == null || campaignsFolder.Children.Count == 0)
            {
                return null;
            }

            var utmCampaign = campaignsFolder.Children.FirstOrDefault(c => c.TemplateName == SitecoreConstants.UTM_Campaigns.TemplateName && c.Fields[SitecoreConstants.UTM_Campaigns.UTM_Source_Key].Value.ToLower(CultureInfo.InvariantCulture) == HttpContext.Current.Request.QueryString["utm_source"].ToLower(CultureInfo.InvariantCulture));

            if (utmCampaign != null)
            {
                // TODO: may be gone in Sitecore 9, if so try using following code:
                // var defManager = DefinitionManagerFactory.Default.GetDefinitionManager<ICampaignActivityDefinition>(null);
                // return defManager.Get(utmCampaign.ID, System.Globalization.CultureInfo.CurrentCulture);
                // Sitecore.DependencyInjection.ServiceLocator.ServiceProvider.GetDefinitionManagerFactory().GetDefinitionManager<ICampaignActivityDefinition>();
                return Tracker.DefinitionItems.Campaigns[utmCampaign.FieldAsItem(SitecoreConstants.UTM_Campaigns.Linked_Campaign).ID];
            }

            return null;
        }


To register this processor I patched it in a config file to replace the original ProcessQueryStringCampaign processor (of course patching after as a separate processor is also possible in this case):


 <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <starttracking>
        <processor patch:instead="*[@type='Sitecore.Analytics.Pipelines.StartTracking.ProcessQueryStringCampaign, Sitecore.Analytics']" type="Custom.Processors.UtmProcessor, Custom.Site">
      </processor></starttracking>
    </pipelines>
  </sitecore>
</configuration>


Of course these templates and processor can be extended to also set your campaign facets as described in this blog.

You could even take this one step further and adjust your pipeline to create a campaign on the fly if there is no matching campaign for your UTM parameters and after creation enroll your visitor(s) in this campaign.

With this small optimization, it becomes a bit easier for your marketer to facilitate both their GA and Sitecore toolset to measure performance of their site.

Reacties

Een reactie posten

Populaire posts van deze blog

I Robot - Sitecore JSS visitor identification

Sitecore JSS - Sitecore first