How to get the Page Visits from XConnect

Often when we build something like sliders or grids which hold teasers for content or product pages, customers want to have the possibility to sort it. Often there should be a sorting by popularity – which means counting the page visits.

To implement such a ranking we need to find out the page visits of the related content or product pages. Following is an example of getting the page visit count for a specific item identified by item ID.

/// <summary>
/// Gets the page visits from a specific page item id.
/// </summary>
/// <param name="itemId">
/// The item from the page to get the visits for.
/// </param>
/// <param name="uniqueVisits">
/// Flag if only one page visit should be count from an interaction.
/// </param>
/// <returns>
/// Returns the total count of visits from a page.
/// </returns>
public int GetPageVisitsByPage(ID itemId, bool uniqueVisits = true)
{
    IAsyncQueryable<Interaction> queryable;
 
    using (XConnectClient client = SitecoreXConnectClientConfiguration.GetClient())
    {
        queryable = client.Interactions.Where(x =>
            x.Events.OfType<PageViewEvent>().Any(y =>
                y.ItemId == itemId.Guid));
    }
 
    IEntityBatchEnumerator<Interaction> enumerable =
        queryable.GetBatchEnumeratorSync();
 
    int totalCount = 0;
 
    while (enumerable.MoveNext())
    {
        foreach (Interaction interaction in enumerable.Current)
        {
            int pageVisits = interaction.Events.OfType<PageViewEvent>()
                .Count(x =>
                    x.ItemId == itemId.Guid &&
                    x.ItemLanguage == Sitecore.Context.Language.Name);
 
            if (uniqueVisits)
            {
                pageVisits = pageVisits > 0 ? 1 : 0;
            }
 
            totalCount += pageVisits;
        }
    }
 
    return totalCount;
}

You also can find this in the Sitecore documentation: https://doc.sitecore.com/developers/91/sitecore-experience-platform/en/get-interaction-events.html

This is all – but what if we implemented wildcard items? Then we have to find out which product item related to the current wildcard item was called to get the correct page visits count.

Therefore we have to replace the CreatPage Processor from Sitecore in the <initializeTracker> pipeline with our own. Here is our example:

/// <summary>
/// Represents the create page processor to fix wildcard items.
/// </summary>
public class CreatePage : InitializeTrackerProcessor
{
    /// <summary>
    /// Create and initialize the page.
    /// </summary>
    /// <remarks>
    /// Copied from sitecore <see cref="Sitecore.Analytics.Pipelines.InitializeTracker.CreatePage"/>.
    /// </remarks>
    /// <param name="args">
    /// The initialize tracker args.
    /// </param>
    public override void Process(InitializeTrackerArgs args)
    {
        Assert.ArgumentNotNull(args, "args");
 
        if (args.IsSessionEnd)
        {
            return;
        }
 
        HttpContextBase httpContext = args.HttpContext;
 
        if (httpContext == null)
        {
            args.AbortPipeline();
        }
        else
        {
            this.CreateAndInitializePage(
                httpContext, args.Session.Interaction);
        }
    }
 
    /// <summary>
    /// Createss and initialize the page context.
    /// </summary>
    /// <param name="httpContext">
    /// The http context.
    /// </param>
    /// <param name="visit">
    /// The current interaction.
    /// </param>
    private void CreateAndInitializePage(
        HttpContextBase httpContext, CurrentInteraction visit)
    {
        IPageContext pageContext = visit.CreatePage();
        pageContext.SetUrl(WebUtil.GetRawUrl());
 
        DeviceItem device = Context.Device;
 
        if (device != null)
        {
            pageContext.SitecoreDevice.Id = device.ID.Guid;
            pageContext.SitecoreDevice.Name = device.Name;
        }
        else
        {
            pageContext.SitecoreDevice.Id = Guid.Empty;
            pageContext.SitecoreDevice.Name = string.Empty;
        }
 
        // Default Sitecore implementation
        Item item = Context.Item;
 
        /* CUSTOM WILDCARD LOGIC */
        if (item?.IsWildcardItem() != null)
        {
            // Perform a call to the logic which resolves the correct item
            Item resolvedItem = this.ResolveWildcardItem(item);
 
            if (resolvedItem != null)
            {
                item = resolvedItem;
            }
        }
        /* CUSTOM WILDCARD LOGIC END */
 
        if (item == null)
        {
            return;
        }
 
        pageContext.SetItemProperties(
            item.ID.Guid, item.Language.Name, item.Version.Number);
    }
 
    /// <summary>
    /// Gets the related sitecore item.
    /// </summary>
    /// <param name="item">
    /// The context item.
    /// </param>
    /// <returns>
    /// Returns the related sitecore item.
    /// </returns>
    private Item ResolveWildcardItem(Item item)
    {
        return Sitecore.Context.Item;
    }

Actually, the only thing we do is overwriting the ResolveWildcardItem method. Once, we implemented our processor we can patch it in the config.

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <initializeTracker>
        <processor patch:instead="processor[@type='Sitecore.Analytics.Pipelines.InitializeTracker.CreatePage, Sitecore.Analytics']"
                   type="MySitecoreProject.CreatePage, MySitecoreProject" />
      </initializeTracker>
    </pipelines>
  </sitecore>
</configuration>

Now our Processor is used and we accomplished the following:

  • Tracks the correct items
  • Fixed items in Experience Profile view
  • Fixed paths in the Path AnalyzeR

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.