A colleague of mine has been looking at some custom page events and reporting in Sitecore 8.1 recently. One thing which came to light during this work is that some of the personalisation rule code in the product didn't appear to work as expected. In case anyone else is looking at this aspect of the software, he's a summary of the issue we were seeing, in the hope that it can help you avoid the time we spent looking into this:
With 8.1, one of the new features for analytics is the ability to write rules which can detect Page Events (or Goals) in either the current session or a previous session. The one we were looking at was:
This is supposed to allow you to trigger a personalisation when a certain page event has been recorded for the current user, and it's custom data matches the criteria specified. However we found that this did not work as expected.
When we set up test data for this rule in 8.1 Update 3 and tried it out, we noted that:
Cue some head-scratching, and a bit of debugging...
The rule's logic is part of the
PageEventWithCustomDataWasTriggeredDuringPastOrCurrentInteractionCondition
class (Snappy name, huh?) in the Sitecore.Analytics.Rules.Conditions namespace. So we grabbed our trusty decompiler and looked through what this code was doing when a rule is evaluated. Through inheritance, this class makes use of the same
Execute()
method as the
PageEventWasTriggeredDuringPastOrCurrentInteractionCondition
class. That code, tidied up a bit, looks like:
protected override bool Execute(T ruleContext) { // -- snip if (this.HasEventOccurredInInteraction((IInteractionData) Tracker.Current.Session.Interaction)) { return true; } // -- snip return this.FilterKeyBehaviorCacheEntries(Tracker.Current.Contact.GetKeyBehaviorCache()).Any<KeyBehaviorCacheEntry>((Func<KeyBehaviorCacheEntry, bool>) (entry => { Guid id = entry.Id; Guid? pageEventGuid = this.PageEventGuid; if (pageEventGuid.HasValue) { return id == pageEventGuid.GetValueOrDefault(); } return false; })); }
Based on that, if the event happened in the current session then only the
HasEventOccurredInInteraction()
method is called. If not, the
FilterKeyBehaviorCacheEntries()
method is called. Digging deeper
FilterKeyBehaviorCacheEntries()
‘s behaviour depends on which rule is being run (it may or may not filter based on custom event data, depending on whether you're using the "with custom data" version of the rule or not).
But
HasEventOccurredInInteraction()
does not have any code that looks at the custom data, and it makes no reference to the
FilterKeyBehaviorCacheEntries()
method which does. It looks like this:
protected override bool HasEventOccurredInInteraction(IInteractionData interaction) { // -- snip return ((IEnumerable<Page>) interaction.Pages).SelectMany<Page, PageEventData>((Func<Page, IEnumerable<PageEventData>>) (page => page.PageEvents)).Any<PageEventData>((Func<PageEventData, bool>) (pageEvent => { if (pageEvent.IsGoal) { return false; } Guid eventDefinitionId = pageEvent.PageEventDefinitionId; Guid? pageEventGuid = this.PageEventGuid; if (pageEventGuid.HasValue) { return eventDefinitionId == pageEventGuid.GetValueOrDefault(); } return false; })); }
That code seems to explain the behaviour we've been seeing – the logic is actually different depending on whether the Page Event fired in the current session or not...
Having spent a bit of time discussing this issue with Sitecore Support, they have agreed that this isn't the right behaviour and have raised a bug. If you encounter this issue, get in touch with support and ask about the fix for issue 118236. They can provide a patch which replaces this rule, and should resolve this problem until the fix can be rolled into a future release.