< Return to Feed
Phillip Berglund - 02.26.2018

Implementing Query String-Based Personalization Rules in FXM

Recently I was asked by a client how to implement Query String-based personalization rules in Federated Experience Manager (FXM).

If you are unfamiliar with Sitecore or FXM you can read about it in great detail here. The basics are that by including a generated script on an external site you can use your Sitecore instance to add or replace content, capture click actions and track user interaction on a separate site – whether it runs on Sitecore or not.

For this task we wanted to configure a piece of information, say an office’s address, on externalsite.com depending on where the user came from via querystring. So the link from remotesiteone.com would link to externalsite.com?location=US and remotesitetwo.com might link as externalsite.com?location=CA.

Note you could also accomplish this specific example using the Referrer rule built into FXM but the actual implementation was a little more complicated than that.

Now,  the way the placeholder content personalization rules work in FXM are just the same as in the Experience Editor for Sitecore content. And as with most things Sitecore, we can add and extend the implementations Sitecore provides for the rules. In our case, we will make a new rule which inherits from the built-in generic Sitecore class StringOperatorCondition<T> where T : RuleContext.

We add two public properties Key and Value and then implement the Execute override method.

1.    public class QueryStringCondition <T> : StringOperatorCondition <T> where T : RuleContext 
2.    {  
3.        public string Key { get; set; }  
4.        public string Value { get; set; }  
5.        protected override bool Execute(T ruleContext) {}  
6.    }  

Now we add the code to pull the querystring and check the value.

1.    Assert.ArgumentNotNull(ruleContext, "ruleContext");  
2.    Assert.IsNotNull((object) this.Key, "Rule must provide a header key to match.");  
3.    Assert.IsNotNull((object) this.Value, "Rule must provide a value to match.");  
4.    var queryStringValue = HttpContext.Current.Request.QueryString[Key];
5.    if (!string.IsNullOrEmpty(queryStringValue)) {  
6.        return this.Compare(queryStringValue, this.Value);  
7.    } 

Now, for the standard Sitecore instance this rule is mostly complete. We have determined that the required parameters are not empty, and we have a value. The compare method on line 6 above comes from the StringOperatorCondition base class and will use the configured comparison method the user selects when creating the condition.

But this does not help us for FXM because our querystring is not in the current request. The current request is to the beacon script FXM uses for external sites to communicate with the Sitecore instance. But Sitecore doesn’t leave us in the dark as to where the request originally came from so we are just going to have to go a little bit deeper into the current request.

1.    var url = System.Web.HttpContext.Current.Server.UrlDecode(WebUtil.GetRawUrl());  
2.    if (!string.IsNullOrWhiteSpace(url))
3.    {
4.        var index = url.IndexOf($"{Key}=", StringComparison.InvariantCultureIgnoreCase);  
5.        if (index > 0)
6.        {
7.            var queryStrings = HttpUtility.ParseQueryString(url);  
8.            var pageQs = queryStrings["page"];  
9.            if (!string.IsNullOrWhiteSpace(pageQs))
10.            {  
11.                try {  
12.                    var pageUri = new Uri(pageQs);  
13.                    var pageQueryStrings = HttpUtility.ParseQueryString(pageUri.Query);  
14.                    queryStringValue = pageQueryStrings[Key];  
15.                }
16.                catch (UriFormatException ufe)
17.                {
18.                    //failed to format uri, do nothing  
19.                }
20.                catch (Exception e) {  
21.                    Sitecore.Diagnostics.Log.Error($"Could not process QueryStringCondition
22.                    for page value - { pageQs }", e, typeof(QueryStringCondition < T > ));  
23.                }  
24.            }  
25.        }  
26.    }
28.    if (string.IsNullOrEmpty(queryStringValue)) {  
29.        return false;  
30.    }
32.    return this.Compare(queryStringValue, this.Value);  

Ok, large code block, so let’s walk through it a bit. First off, we UrlDecode the RawUrl using Sitecore’s WebUtil class. If that is not null or empty, we check for the querystring key the user configured. If we have it, we parse the querystring of the URL and pull the “page” parameter. This is where FXM puts the original URL from the external site. Once there, it is more of the same—parse that URL’s querystrings and look for ours. Finally, we check to see if we have a value. If we didn’t have a value we short circuit and return as false, but otherwise we use the base compare method again.

So now we have a wonderful class that can handle querystring parameters for the regular Sitecore instance and FXM—two birds, one stone. But how are we going to use it in either of those? Create the necessary items, of course.

Navigate to /sitecore/system/Settings/Rules/Definitions/Tags and add a new /sitecore/templates/System/Rules/Taxonomy/Tag With the appropriate name for your rule.

In the sitecore instance, duplicate an existing Element Folder in /sitecore/system/Settings/Rules/Definitions/Elements

Rename and configure the /sitecore/templates/System/Rules/Condition with the Text field as:

1.    where request query string[Key, , , key][operatorid, StringOperator, , compare to][Value, , , value]  

The Key, operatorid and Value string sin brackets are the rules engine implementation and will be interpreted for you. Note that if you wish to change form the Key Value naming convention you can do so by changing your properties and the values in these brackets. They just need to match each other.

Then in the Script field section find the Type field and put the fully qualified name for your class.

Then under the Tags Definitions folder, select the Default Tags Definition and in the left pane of the multilist select your new tag.

One last step and we are ready to go to FXM.

Go to /sitecore/system/Settings/Rules/Conditional Renderings/Tags/Default and in the left pane of the multilist select your tag again. This configures the rules availability in the personalize modal to include your rule.

At this point I recommend you publish the newly created items.

Now we just need to add it to a page and configure some parameters. The above link will provide all the detail you need to set up your site in FXM and add the placeholder, so I will not cover that here, but I will leave you with a screenshot of how it should look once configured.