<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Sitecore Xperiences &#187; Analytics</title>
	<atom:link href="https://blog.peplau.com.br/category/analytics/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.peplau.com.br</link>
	<description>The things I&#039;ve seen as a Sitecore Professional</description>
	<lastBuildDate>Sun, 09 Mar 2025 21:54:22 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.1.41</generator>
	<item>
		<title>Custom rule condition to find Top-N Profile Key</title>
		<link>https://blog.peplau.com.br/custom-rule-condition-to-find-top-n-profile-key/</link>
		<comments>https://blog.peplau.com.br/custom-rule-condition-to-find-top-n-profile-key/#comments</comments>
		<pubDate>Mon, 09 Sep 2019 17:19:01 +0000</pubDate>
		<dc:creator><![CDATA[Rodrigo Peplau]]></dc:creator>
				<category><![CDATA[Analytics]]></category>
		<category><![CDATA[Rules]]></category>
		<category><![CDATA[xDB]]></category>

		<guid isPermaLink="false">http://blog.peplau.com.br/?p=792</guid>
		<description><![CDATA[<div class="lr_horizontal_share" data-share-url="https://blog.peplau.com.br/custom-rule-condition-to-find-top-n-profile-key/"></div>Here we are for another simple yet useful tip from the Smart Bookshelf Demo. Although we are now improving it with some Artificial Intelligence, the first version has Sitecore Rules-based Personalization in the hearth of the recommendation mechanism. Our desired behavior is to light-up LED strips from the top 3 Book Genres, such as seen below: The books you see on [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Here we are for another simple yet useful tip from the Smart Bookshelf Demo. Although we are now improving it with some Artificial Intelligence, the first version has Sitecore Rules-based Personalization in the hearth of the recommendation mechanism.</p>
<p>Our desired behavior is to light-up LED strips from the top 3 Book Genres, such as seen below:</p>
<p><img class="alignnone wp-image-795 size-large" src="http://blog.peplau.com.br/wp-content/uploads/Face-Detection-picture-1024x539.jpg" alt="Face Detection picture" width="605" height="318" /></p>
<p>The books you see on screen are shown according to the top 3 genres for the current visitor.</p>
<p>It automatically scrolls, showing one genre each time. Here is how the component looks like:</p>
<p><a href="http://blog.peplau.com.br/wp-content/uploads/Recommended-Books.jpg"><img class="alignnone wp-image-793 size-full" src="http://blog.peplau.com.br/wp-content/uploads/Recommended-Books.jpg" alt="Recommended Books" width="670" height="709" /></a></p>
<p>Our content tree is composed by Genre Pages, each of them with respective Profile Card assigned:</p>
<p><a href="http://blog.peplau.com.br/wp-content/uploads/Mapping-Genres-and-Profile-Cards.jpg"><img class="alignnone wp-image-797" src="http://blog.peplau.com.br/wp-content/uploads/Mapping-Genres-and-Profile-Cards-1024x412.jpg" alt="Mapping Genres and Profile Cards" width="1025" height="412" /></a></p>
<p>So when your visitor visits a Genre Page, he or she will get points for that respective Profile Card, enabling Sitecore to register and track what are the preferred genres. The same thing also happens when a Book Page is visited (achieved by <a href="http://blog.peplau.com.br/en_US/programmatically-visit-a-page-and-all-xdb-related/" target="_blank">using the technique explained in my last post</a>).</p>
<p>At this point we are already able to see preferred genres for our contacts, by opening any known contact at the Experience Profile:</p>
<p><a href="http://blog.peplau.com.br/wp-content/uploads/Experience-Profile-shows-preferred-Genres.jpg"><img class="alignnone size-medium wp-image-798" src="http://blog.peplau.com.br/wp-content/uploads/Experience-Profile-shows-preferred-Genres-273x300.jpg" alt="Experience Profile shows preferred Genres" width="273" height="300" /></a></p>
<p>&nbsp;</p>
<h2>Rules Conditions</h2>
<p>We will retrieve the top 3 genres by using Rules-based Personalization. What you see below is the personalization setting required to display the Poetry Genre if it&#8217;s &#8220;top 2&#8243; for the current Visitor.</p>
<p><a href="http://blog.peplau.com.br/wp-content/uploads/Custom-Rule-Condition.jpg"><img class="alignnone wp-image-799 size-full" src="http://blog.peplau.com.br/wp-content/uploads/Custom-Rule-Condition.jpg" alt="Custom Rule Condition" width="549" height="143" /></a></p>
<p>&nbsp;</p>
<h2>Custom Rule Condition: Matches Pattern Best X</h2>
<p>Our custom condition is based on this OOTB condition:</p>
<pre>/sitecore/system/Settings/Rules/Definitions/Elements/Visitor/Matches Pattern</pre>
<p>However, it can only match match top 1, while our new condition accepts a number to test against.</p>
<p>&nbsp;</p>
<h3>Definition Item</h3>
<ul>
<li><strong>Path:</strong> <em>/sitecore/system/Settings/Rules/Definitions/Elements/Visitor/Matches Pattern Best X</em></li>
<li><strong>Template:</strong>  <em>/sitecore/templates/System/Rules/Condition</em></li>
<li><strong>Text:</strong> where the current contact matches best [value,Text,,specific value] on profile key [ProfileKey,ProfileKey,,profile key]</li>
<li><strong>Type:</strong> Your.Namespace.Rules.Conditions.ContactPatternMatchBestCondition, Your.AssemblyName
<ul>
<li><em>Make sure this points to your correct namespace</em></li>
</ul>
</li>
</ul>
<p>&nbsp;</p>
<h3>Source Code</h3>
<p>Here is the source code to implement this condition. After setting up the Definition Item, as described at the previous topic, all you need to use it is to compile it.</p>
<pre>using Sitecore.Abstractions;
using Sitecore.Analytics;
using Sitecore.Analytics.Tracking;
using Sitecore.Data;
using Sitecore.Framework.Conditions;
using Sitecore.Rules;
using Sitecore.Rules.Conditions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Sitecore.Diagnostics;

namespace Your.Namespace.Rules.Conditions.ContactPatternMatchBestCondition
{
   public class ContactPatternMatchBestCondition&lt;T&gt; : WhenCondition&lt;T&gt; where T : RuleContext
   {
      // ID for the item /sitecore/system/Settings/Content Testing/Personalization Suggestions/No pattern match
      private readonly ID _noPatternMatchItemId = ID.Parse("9E05C456-5CD0-405B-9D45-31DDD92AB8E4");
      private string _profileKey;
      public ContactPatternMatchBestCondition() : this(DependencyResolver.Current.GetService&lt;BaseLog&gt;()) { }

      internal ContactPatternMatchBestCondition(BaseLog log) {
         Condition.Requires&lt;BaseLog&gt;(log, nameof(log)).IsNotNull&lt;BaseLog&gt;();
         this.Log = log;
      }

      private string _value;
      public string Value {
         get =&gt; _value ?? string.Empty;
         set {
            Assert.ArgumentNotNull(value, nameof(value));
            _value = value;
         }
      }

      public string ProfileKey {
         get =&gt; _profileKey;
         set =&gt; _profileKey = value ?? string.Empty;
      }

      internal BaseLog Log { get; }

      protected override bool Execute(T ruleContext) {
         Condition.Requires&lt;T&gt;(ruleContext, nameof(ruleContext)).IsNotNull&lt;T&gt;();
         Condition.Ensures&lt;ITracker&gt;(Tracker.Current, string.Format("{0}.{1}", (object)"Tracker", 
            (object)"Current")).IsNotNull&lt;ITracker&gt;();
         Condition.Ensures&lt;Session&gt;(Tracker.Current.Session, string.Format("{0}.{1}.{2}", (object)"Tracker", 
            (object)"Current", (object)"Session")).IsNotNull&lt;Session&gt;();
         Condition.Ensures&lt;Contact&gt;(Tracker.Current.Session.Contact, string.Format("{0}.{1}.{2}.{3}", 
            (object)"Tracker", (object)"Current", (object)"Session", (object)"Contact")).IsNotNull&lt;Contact&gt;();
         if (string.IsNullOrEmpty(this.ProfileKey))
            return false;
         IEnumerable&lt;IBehaviorProfileContext&gt; profiles = Tracker.Current.Session.Contact.BehaviorProfiles.Profiles;
         List&lt;ID&gt; idsList = this.GetIdsList(this.ProfileKey);
         if (!profiles.Any&lt;IBehaviorProfileContext&gt;() &amp;&amp; idsList.Contains(this._noPatternMatchItemId))
            return true;
         if (!idsList.Any())
            return false;

         var profileKeyId = idsList.First();

         int best;
         if (!int.TryParse(Value, out best))
            return false;

         foreach (IBehaviorProfileContext profile in profiles) {
            var profileScores = GetProfileKeyValue(profile);
            if (profileScores.Count &lt; best)
               return false;

            var index = best - 1;
            var specifiedBest = profileScores[index].Key;
            var specifiedValue = profileScores[index].Value;
            var isBest = specifiedBest == profileKeyId &amp;&amp; specifiedValue&gt;0;
            if (isBest)
               return true;
         }
         return false;
      }

      private List&lt;KeyValuePair&lt;ID,double&gt;&gt; GetProfileKeyValue(IBehaviorProfileContext profile) {
         if (profile == null)
            return new List&lt;KeyValuePair&lt;ID,double&gt;&gt;();

         // ISSUE: explicit non-virtual call
         var ret = profile.Scores.ToList();
         ret.Sort((pair1,pair2) =&gt; pair2.Value.CompareTo(pair1.Value));
         return ret;
      }

      private List&lt;ID&gt; GetIdsList(string idList) {
         string[] strArray = idList.Split(new char[1] { '|' }, StringSplitOptions.RemoveEmptyEntries);
         var idList1 = new List&lt;ID&gt;();
         foreach (string str in strArray) {
            if (!string.IsNullOrEmpty(str)) {
               ID id = ID.Parse(str, ID.Null);
               if (!ID.IsNullOrEmpty(id))
                  idList1.Add(id);
            }
         }
         return idList1;
      }
   }
}</pre>
<p>Hope you enjoy it!</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.peplau.com.br/custom-rule-condition-to-find-top-n-profile-key/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Programmatically &quot;Visit&quot; a page (and all xDB-related)</title>
		<link>https://blog.peplau.com.br/programmatically-visit-a-page-and-all-xdb-related/</link>
		<comments>https://blog.peplau.com.br/programmatically-visit-a-page-and-all-xdb-related/#comments</comments>
		<pubDate>Thu, 05 Sep 2019 02:36:45 +0000</pubDate>
		<dc:creator><![CDATA[Rodrigo Peplau]]></dc:creator>
				<category><![CDATA[Analytics]]></category>
		<category><![CDATA[xDB]]></category>

		<guid isPermaLink="false">http://blog.peplau.com.br/?p=779</guid>
		<description><![CDATA[<div class="lr_horizontal_share" data-share-url="https://blog.peplau.com.br/programmatically-visit-a-page-and-all-xdb-related/"></div>Yesterday during my presentation at the SUG-Quebec (check video here), my host and good friend Jeff L&#8217;Heureux asked if I could share the multiple challenges involved in the Smart Bookshelf for Sitecore Demo. In response to that, I&#8217;m putting together a number of articles, modules and other resources, to share how each of these things works. The present article [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Yesterday during my presentation at the SUG-Quebec (<a href="https://youtu.be/Ji64QkGQqFI" target="_blank">check video here</a>), my host and good friend <a href="https://twitter.com/jflh" target="_blank">Jeff L&#8217;Heureux</a> asked if I could share the multiple challenges involved in the Smart Bookshelf for Sitecore Demo. In response to that, I&#8217;m putting together a number of articles, modules and other resources, to share how each of these things works.</p>
<p>The present article shows how we can simulate a visit to a Sitecore page, along with all xDB-related events that happens when you actually do it. For instance, if your page has Profile Card(s) associated, then your contact should get points in that profile when the page is visited.</p>
<p>The Smart Bookshelf has the following situation:</p>
<p><a href="http://blog.peplau.com.br/wp-content/uploads/Anthology-Profile-Cards.jpg"><img class="alignnone wp-image-780 size-full" title="Anthology Profile Cards" src="http://blog.peplau.com.br/wp-content/uploads/Anthology-Profile-Cards.jpg" alt="Anthology Profile Cards" width="840" height="423" /></a></p>
<p>As you can see, <strong>Genres have corresponding Profile Cards, </strong>so when a Genre page is visited, the corresponding Profile Card is summed up to the contact&#8217;s profile. This is how we can track and define the user&#8217;s preferred Book Genres.</p>
<p>Now we want to apply the same <span style="text-decoration: underline;">Genre Profile Cards</span> when the user visits a <span style="text-decoration: underline;">Book Page</span>. Given that each book belongs to a single Genre, we don&#8217;t have to manually associate the Profile Card to individual books. Instead, we can use the following technique to simulate a visit to a Genre Page when a Book is visited.</p>
<p>&nbsp;</p>
<h2>Enough talking &#8211; show me the code!</h2>
<p><a href="http://blog.peplau.com.br/wp-content/uploads/YTvASAn1.gif"><img class=" wp-image-782 size-full alignnone" src="http://blog.peplau.com.br/wp-content/uploads/YTvASAn1.gif" alt="Ozzy Rock" width="432" height="352" /></a></p>
<p>So simple and easy, that you&#8217;ll probably want to kill me for the long intro</p>
<p>&nbsp;</p>
<p><strong>Step 1</strong> &#8211; Get the item you want to simulate a visit to</p>
<p>In my case, Books are direct children of Genres, so all I have to do is to get the parent item:</p>
<pre>var bookItem = Sitecore.Context.Item;
var genreItem = bookItem.Parent;</pre>
<p><strong>Step 2</strong> &#8211; Simulate the visit</p>
<p>Go ahead and call the following static method:</p>
<pre>Sitecore.Analytics.Data.TrackingFieldProcessor.Process(genreItem);</pre>
<p><a href="http://blog.peplau.com.br/wp-content/uploads/5qOq1.gif"><img class=" wp-image-783 size-full alignnone" src="http://blog.peplau.com.br/wp-content/uploads/5qOq1.gif" alt="Thats it?" width="498" height="498" /></a></p>
<p>Yes! You want it harder?</p>
<p><a href="http://blog.peplau.com.br/wp-content/uploads/giphy1.gif"><img class=" wp-image-784 size-full alignnone" src="http://blog.peplau.com.br/wp-content/uploads/giphy1.gif" alt="Minions saying NO!" width="337" height="337" /></a></p>
<p>Thought so <img src="https://blog.peplau.com.br/wp-includes/images/smilies/icon_wink.gif" alt=";)" class="wp-smiley" /></p>
]]></content:encoded>
			<wfw:commentRss>https://blog.peplau.com.br/programmatically-visit-a-page-and-all-xdb-related/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
