Sitecore Personalize uses goals to track the performance of experiences and experiments. But what happens if your experience is live and you don’t see any executions or goals tracked in the performance tab for the experience? It can be hard to debug, test and troubleshoot goal tracking especially if the experience is hidden behind a login for example. But you can trigger the goal programmatically by making a series of api calls. I’ve created a Postman collection that you can download to make the process easy! Just update the environment with the appropriate values and you’ll be able to trigger your goals in no time!
Create your experience using any variant, page targeting and filtering settings. Expand the goals section and ensure “track performance” is selected, then click Add goals. In this example, I’m using a custom goal. Give your goal a name and set your performance targets. Add the name of your custom event under “track event” and click the save button.
Make sure to preview your experience to ensure it displays properly. But keep in mind that an experience must be live in order for the system to track goals.
In order to trigger a goal in Sitecore Personalize the experience must be viewed in the same session as the goal event. I’ve setup a postman collection that simulates a user navigating the site, triggering the experience and executing the custom event.
In order to track your guest, you need a browser id (even for api calls). You can obtain a new browser id by using the “Get Browser Id” call in the postman collection or by using your existing browser id from your browser. To get your existing browser id, open your browsers dev tools and enter the following command in the console.
engage.getBrowserId()
You can update the environment vars in the postman collection to use your existing browser id.
Once you have your browser id, we will simulate the user journey through the site. I have included 5 page view calls in the postman collection along with 5 page variables. Set the urls of the pages you want to call, then execute the VIEW requests.
After you have made a few view requests, you’ll want to trigger the experience. You’ll need the friendly id of the experience which can be found on the experience page in the grey details box. Add this name in the environment variables for the postman collection the run the “Trigger Experience” request.
Once the experience is triggered, you can trigger your custom event. Add the custom event name and page url to the environment variables, then execute the “Custom Event” request.
In this example, we have triggered a goal for an experience using a custom event. You can just as easily trigger a page view goal by executing a VIEW request to the proper page after triggering your experience. Similarly, you may want to trigger the identity event if your experience requires the user to log into your site.
It is important to note that the goal will not appear on the report until the browsing session is closed! Your point of sale has a timeout period that will close a browsing session after X minutes of inactivity. When you are testing, you can execute the FORCE CLOSE request to end the session manually.
Once you have triggered the goal and the session has ended, check the performance and operational data of the experience to validate the goal was triggered properly. You will see the successful execution of the experience in one graph
and the primary goal in a separate graph.
You can now be confident that your goal is configured correctly and Sitecore Personalize is tracking your goal correctly.
]]>Welcome to my recap of Sitecore Symposium 2024! The week continued with numerous insightful sessions, informative workshops, and exciting new announcements. Here are my session notes and takeaways from the final day at Symposium, day three.
Opening keynote with Brendan Hunt
The morning kicked off on a high note with a special guest appearance by Brendan Hunt, who plays Coach Beard on Ted Lasso. Though I haven’t watched the show myself—there are simply too many good ones to keep up with —I still found his insights engaging and relevant. He shared valuable lessons that resonate in both work and life, without needing to be star-struck to appreciate them.
CDP and Personalize at Scale session
Personalization at scale holds immense potential for boosting revenue, and companies that successfully tackle the challenges of scaling personalization will gain a competitive edge. In today’s market, can your business afford not to invest in personalization? While personalization can drive growth, it comes with its own set of challenges—overcoming these will set industry leaders apart from the rest.
The benefit of a SaaS-based product like XM Cloud is that it is being continuously updated. Best of all you get the updates without having to upgrade. XM Cloud has numerous new features coming to the platform.
Lunch with friends in the Sitecore community
What a great way to end a great week! An in-person Sitecore lunch started as two tables and then grew to four, six, and eight tables with almost 40 people. This shows the real power of the Sitecore community because although we might work for different companies and be considered “competition”, we can still be friends and discuss Sitecore without boundaries. With my Perficient colleagues, it’s so nice to sit around a physical table with everyone that I normally see every week in little boxes on a Zoom call.
Sitecore Symposium 2024 is over, but there is so much to look forward to in the world of Sitecore over the next year. I’m thrilled about the upcoming changes in CDP, Personalize, and Search with unified tracking, as well as the potential of Sitecore Stream for AI-driven insights, content creation, and brand-aware marketing support. I’m also looking forward to the Sitecore Marketplace, where we can build apps and expand the capabilities of XM Cloud. Feel free to connect with me on LinkedIn. I’d love to chat and hear more about what Sitecore news you are most excited about.
]]>Welcome to my recap of Sitecore Symposium 2024! Day 2 at Symposium offered incredible insights and valuable information. There was no shortage of engaging sessions and thought-provoking discussions and we are so excited to bring these fresh perspectives back. Here are my session notes and takeaways from day two.
What an inspiring way to start the day! Sitecore and Perficient joined to bring the inaugural Women in Digital Breakfast to life. The morning started with a nice breakfast buffet and there was time to hang out and connect with other attendees. Perficient continued our “Skip the Swag” initiative and left notecards on the tables where each attendee could write and share how cancer has impacted their life. For each attendee, Perficient will make a donation on their behalf to the American Cancer Society. The panel discussion was very well done and the speakers had great insight and takeaways.
Eric Stine opened the day with the announcement that Content Hub, XM Cloud, and CDP are all HIPPA compliant! This is a big deal since it allows Sitecore to be able to sign BA agreements with healthcare organizations. In today’s modern world, users expect personalized experiences but this is difficult when it comes to PHI. You cannot change your personal information like you can your credit card if you get hacked. Protecting personal information is important to a brand’s trust.
The morning continued with the announcement of the Experience Award winners for 2024. Perficient was pleased to win the Global Sitecore Practice Excellence Award. You can see a full list of all the winners in Sitecore’s official press release. Congratulations to all the winners!
This project included 6 sources, 7000 PDFs, and 44 languages! How do you scale Sitecore Search to a project that large?
More people are moving to XM Cloud and other SaaS products. 82% of users say that an app marketplace is an important factor in choosing a DXP platform. Sitecore is taking that information to heart and creating a new Sitecore Marketplace. This will be a fully supported solution for discovering, enabling, and managing apps, plugins, and extensions.
Sitecore’s composable suite of products are becoming easier to connect together. Unified tracking means that you only must integrate one SDK. It also means that each event triggered will persist across all Sitecore products. The first products to use unified tracking will be XM Cloud, CDP, Personalize, and Search.
Sitecore sure knows how to throw a party! We had bus service to downtown Nashville where we had space at four bars on Broadway just for attendees! There was a buffet with all the southern comforts including my favorites: chicken and waffles and shrimp and grits! To top it off, there were three floors of entertainment and a rooftop with a view of downtown. There was live music, line dancing, drinks, and good times with good friends! What a great night and great experience at Sitecore Symposium!
]]>Welcome to my recap of day one at Sitecore Symposium 2024! There was no shortage of inspiring sessions, key takeaways, and exciting announcements from day one.
The opening keynote by Sitecore executives was an excellent kickoff to Symposium, reinforcing their commitment to being a trusted partner. They emphasized their focus on core strengths and want people to have a choice, whether it be XM Cloud, XM, or XP. Sitecore is determined to stay ahead of the market through innovation and they made several exciting announcements about the direction they’ll take in the coming year. It’s an exciting time to be working with Sitecore!
Introducing Sitecore Stream! Sitecore Stream is the new brand-aware AI generative copilot that will work with marketers as they try to do more with less.
It really is an impressive tool and I, along with many others in the Sitecore community, can’t wait to see it in action. You really do have to see it to believe it.
Accessibility is more important than ever, yet it’s often treated as an afterthought, typically addressed at the end of projects when it should be prioritized from the start. It’s not just about checking a box or a one-and-done effort—accessibility affects everyone and can benefit anyone. Good website design enhances the user experience for all, not just those with disabilities.
Bias is an unfavored weight towards one group of people. How does this affect generative AI? Test it yourself: create an image without specifying details like age, gender, or race. What results do you see? Chances are, the image lacks cultural diversity, and representation of people with disabilities, or older individuals. It may also reflect assumptions about gender roles based on job titles.
Sitecore Search is continuously evolving like many other SaaS products. Take a look at the future of Sitecore Search.
A conference like Sitecore Symposium is a great way to make a mini vacation out of your work travels. I arrived on Sunday and explored the city of Nashville. Did you know that Nashville is home to a full-scale replica of the Parthenon? It was built in 1897 as part of the Tennessee Centennial Exposition. Today, it’s the only remaining building from the exposition and has since been turned into a museum. The museum contains the largest indoor statue in the Western Hemisphere, the goddess Athena in full gold leaf standing at 41ft tall.
Symposium is being hosted at the Gaylord Opryland Resort. This is my first time here and the hotel is beautiful. The atrium is covered in glass and has lush green gardens and walking paths with waterfalls. You can even take a boat ride through the interior.
For me, the best part about these conferences is seeing people face-to-face! Most of us work remotely and are only able to see these people on phone calls and little boxes on our screen in a grid on a zoom call. It’s great to see people in person, face-to-face because technology can’t replicate that experience.
Click to view slideshow.The conference schedule fills up quickly, so having time beforehand to hang out with friends is great. Chet Potvin organized a walking food tour of Nashville on Sunday night. We started out at a rooftop bar with a great view of downtown Nashville. The guide shared some great stories about Nashville history, culture, music, and food. We had four stops, which included Nashville barbecue and the famous Nashville hot chicken.
Monday was the MVP Summit. This was my first time attending. While I can’t share any of the information from the sessions, I can say it was a great experience. We got a sneak peek of inside information and got to interact with the Sitecore product teams and executives. We had interactive conversations and it’s great knowing that the team at Sitecore really listens to our feedback. As MVPs, we are really able to impact the products.
After a full day of sessions, we were treated to an MVP party at Dave and Buster’s. Sitecore booked the entire venue just for us. We had great food and drink, unlimited gaming, and karaoke. It was a great time to hang out with old friends and make new friends.
Tiffany, Josh, and I challenged Dave O’flanagan to a race of Mario Kart! MJ is quite the instigator and isn’t afraid to let loose and encourage others to do the same. We did a great version of Ice Ice Baby. And in case you’re curious, yes, we know all the words. The night ended with 15 people singing Closing Time. But we weren’t done yet. On the walk back to the hotel, we gave our best acapella version of Sweet Caroline. It was so good so good so good! What a fun night! It’s the reward for a full year’s worth of hard work to achieve MVP status.
I’m looking forward to seeing what more Sitecore Symposium has to offer. It promises to be full of innovation, collaboration, fresh insights, and informative sessions. If you’re attending Sitecore Symposium, stop by our Perficient booth!
]]>Sitecore CDP tracks user behavior by linking browsing session, events, and orders to a guest profile. By default, guests are marked as “visitors” meaning we do not know who they are. A guest can become a “customer” meaning we know who they are. In order to identify a guest, we must send an “IDENTITY” event. An identity event is a specific type of event that tells Sitecore CDP to begin the identity resolution process. This process is well documented. I read through this documentation multiple times and did not really understand the process until I needed to implement it for myself. If you have been confused by identity in CDP, read on!
A guest profile is created when you browse a site. Your guest profile is linked to your browser through a browser id. By default your guest profile is has the status of visitor. In order to identify as a customer, you must send an IDENTITY event. Any time you collect a piece of information that identifies the person, you can send the IDENTITY event. This event can be the result of logging in, filling out a contact form, or registering for a newsletter. When you send an identity event, you send an identifiers attribute in the event object. This identifiers attribute has properties for provider and id.
var event = { "channel": "WEB", "language": "en", "currency": "USD", "page": window.location.pathname + window.location.search, "email": "clint.barton@shield.gov", "firstname": "Clint", "lastname": "Barton", "identifiers": [ { "id": "clint.barton@shield.gov", "provider": "email" } ] } engage.event("IDENTITY", event);
When you send an IDENTITY event, CDP will store the identity values in the identifiers array of the guest linked to your browser id. CDP will use the string value in the provider property and search all guests for a matching id within the same provider. If none are found, it changes the status of the guest profile to “customer” since it now knows who you are. If it does find another customer with the same provider/id, it merges the current guest visitor profile with the existing guest customer profile. This process is called identity resolution.
The identity resolution process makes more sense if you enable debug mode for CDP and look at the properties of a guest. CDP has an internal property called “identifiers” for each guest. Notice how the properties you sent in the IDENTITY event are stored with the guest.
In the real world, we have multiple ways we can be identified: date of birth, social security number, drivers license id, passport id, email, username, account id, etc. CDP allows the same behavior digitally. Each guest profile can store multiple identifiers.
You can send multiple provider/ids in the identifiers attribute of the IDENTITY event.
var event = { "channel": "WEB", "language": "en", "currency": "USD", "page": window.location.pathname + window.location.search, "email": "clint.barton@shield.gov", "firstname": "Clint", "lastname": "Barton", "identifiers": [ { "id": "clint.barton@shield.gov", "provider": "email" }, { "id": "c_barton", "provider": "username" } ] } engage.event("IDENTITY", event);
CDP uses email by default, but allows you to create up to 5 identity rules.
Identity rules in Sitecore CDP
Imagine that you have an identity rule for username. In CDP you would define a new rule called “username”. When you send an identity event, you can pass {provider: username, id: c_barton}. CDP will store this value in the identifiers property of the guest just like it did with the email. So now guests have two ways they can be identified. CDP does not allow you to set the order of the rules. But you can send the identity providers in the IDENTITY event in the order you want to process them. If CDP does not find a match with the first listed provider, it evaluates all remaining providers in the order listed.
The most important to know that the identity rules and the identity resolution process is that the provider is just a string label. You could call it “abracadabra”, “alohomora”, or “Supercalifragilisticexpialidocious”. Just be sure to send the same string label in the IDENTITY event so the identity resolution process can match guests correctly.
]]>Sitecore Personalize has several out of the box components that notify the user such as popup takeover, corner popup, sidebar, and alert bar. These components all feature a close icon that will hide the component from the screen. But there is no logic out of the box to prevent them from being displayed again.
Imagine we have an alert banner that appears at the top of the page. You use page targeting to run the experience on all pages. This will ensure the user sees the information when they come to the site no matter what page they land on first. The user lands on the contact us page and sees the alert banner. They click the X icon to dismiss the banner and navigate to another page. The banner appears again. They click the X icon to dismiss the banner and navigate to another page. The banner appears again! What a frustrating experience! The user thinks, I don’t want to see this banner again!
Here are two ways that you can track the dismiss event and prevent the banner from appearing after it is dismissed.
Conditions allow you to control when an experience is displayed much like page targeting. A condition is simply a block of javascript code that can access guest data and events. A condition returns true if the experience should display and false if it should not display. This javascript runs server-side. You have access to the full guest context, but not the client’s browser window. You can use the same [[parameter | type | default value ]] syntax as in the experience variant or web template to create a user editable form allowing the condition to be customized.
Imagine our alert banner example. We want to create a condition that searches the guest’s events to see if the alert banner had been dismissed previously. CDP retains all event data from the last 1000 sessions (https://doc.sitecore.com/cdp/en/users/sitecore-cdp/data-availability-in-sitecore-cdp.html). Note that if you have a long running experience on a site where users have a high number of sessions, it could be possible that the alert banner could appear again after the session containing the dismiss event has rotated out of storage. In general, this solution will work across devices once the user has logged in and can tie their session to their guest profile.
(function () { var session = guest.sessions[0]; if (!session) { return true; } for (var j = 0; j < session.events.length; j++) { var data = session.events[j]; if (data.type === "[[Event Name | string | ALERT_BAR_DISMISSED]]") { return false; } } return true; })();
In the output section of the configuration tab, we want to edit the description. Include the parameters in the description so the user can customize the condition for this experience. The description is displayed when the user selects the condition from the experience screen. The parameterized fields will show in bold.
In the preview section at the bottom of the screen, you can see how the text description will be displayed with the bold fields along with a preview of the input mode.
In the web template we will create a parameter that allows the user to give this experience a unique id. This is important so dismissing BannerA does not prevent all future banners from being displayed. Notice in this code that we are adding an event listener on the close button. When the close button is clicked, we are sending an event back into Personalize so the condition can find it the next time the page is loaded. Notice that we can use Engage.settings.pointOfSale so we do not have to hard code that value. This value is read from the Engage SDK in the client’s browser.
document.body.classList.add("show-TopBanner"); insertHTMLBefore('body', 'pers-'); // Declarations const persExperience = document.querySelector("#pers-"+variant.ref+ ' #pers_TopBanner'); const persCloseButton = document.querySelector("#pers-"+variant.ref+ ' .pers__btn-close'); // Declare Pers function event const sendInteractionToPersonalize = function(interactionType){ const type = "[[ Experience ID | String | ALERT_BAR | {required: true}]]_" + interactionType; const eventData = { "channel": "WEB", "pointOfSale": Engage.settings.pointOfSale, }; window.engage.event(type, eventData); } //Listen on X button persCloseButton.addEventListener("click", function(){ persExperience.style.display = "none"; document.body.classList.remove("show-TopBanner"); sendInteractionToPersonalize("DISMISSED") });
When you preview the experience with the condition, the qa tool will show a yellow people mark indicating that it stopped processing at the filter step.
This helps with performance because the decision model is not executed and the html/css step is not rendered.
Let’s imagine our same alert banner but this time using cookies to track if the banner has been dismissed. When we create our experience, we won’t need to set a condition this time. Instead we’ll modify the web template to include a check to see if the cookie exists. We’ll also write a cookie when the alert banner is dismissed. Notice here I’m wrapping the entire javascript block from before inside an if statement that checks for the cookie. You can use the variant.ref variable to dynamically get the GUID of the current variant. We’ll use the variant.ref as the name of our cookie so dismissing BannerA does not prevent all future banners from being displayed.
if (!document.cookie.split(";").some((item) => item.trim().startsWith('pers-' + variant.ref + '='))) { document.body.classList.add("show-TopBanner"); insertHTMLBefore('body', 'pers-'); // Declarations const persExperience = document.querySelector("#pers-" + variant.ref + ' #pers_TopBanner'); const persCloseButton = document.querySelector("#pers-" + variant.ref + ' .pers__btn-close'); // Declare Pers function event const sendInteractionToPersonalize = function (interactionType) { const type = "[[ Experience ID | String | ALERT_BAR | {required: true}]]_" + interactionType; const eventData = { "channel": "WEB", "pointOfSale": Engage.settings.pointOfSale, }; window.engage.event(type, eventData); } //Listen on X button persCloseButton.addEventListener("click", function () { persExperience.style.display = "none"; document.body.classList.remove("show-TopBanner"); sendInteractionToPersonalize("DISMISSED") document.cookie = 'pers-' + variant.ref + '=clicked; max-age=31536000; path=/' }); }
When you preview this experience, the qa tool will show a green check mark indicating that it processed all the steps including the decision model and html steps. Be awared, this could make it more difficult to debug your experiences. If the cookie does not exist, the experience is added to the page. If the cookie does not exist, the experience is not added to the page. There is no UI flicker here because it doesn’t show/hide the experience. Make sure to wrap your entire javascript block in the cookie check so you don’t get null reference errors if your code tries to read elements from the DOM.
This solution helps with performance because it does not require you to search guest session to find a specific event. However, the cookie sits on the client’s browser. In this example, I have set the cookie expiration for one year (31536000). But the experience could display again if the user blocks cookies or they clear their cookies. It is also device specific. If the user moves to another device, the experience will display again. For this reason, it is important to end experiences that are no longer being used so users don’t see experiences with outdated or incorrect information.
Which method you choose to implement will depend on what is best for your use case. If you want to implement either of these options on the out of the box components, you’ll want to create custom web templates by copy/pasting the html/css/javascript of the out of the box component. The out of the box components cannot be modified or duplicated.
]]>I started a new Sitecore Personalize project. The client nonprod and prod environments were freshly spun up. All fresh and clean. No offer templates, no experiences, no decision models. I created the first experience and proceeded to click the preview button to test my experience. To my surprise the experience did not render, and the QA tool did not display. What was the problem? Read on to find out.
I had been testing and doing demos with my partner sandbox account and of course everything worked just fine. I included the Engage SDK javascript on the pages. I set the clientKey and pointOfSale attributes correctly. I created an experience in draft mode. I previewed the experience on a localhost page. The QA tool loaded correctly.
Sitecore Personalize showing the QA tool, the web experience and the network tab of dev tools listing the relevant assets
I compared my partner sandbox to the client environment. I watched the network tab and noticed that the call to https://d1mj578wat5n4o.cloudfront.net/sitecore-engage-v.1.4.0.min.js loaded correctly. This file makes a call to load https://d35vb5cccm4xzp.cloudfront.net/web-flow-libs/<partnerKey>/web-version.min.js. This file makes a call to load https://d35vb5cccm4xzp.cloudfront.net/web-flow-libs/<partnerKey>/34/web-lib.min.js. This file makes a call to load https://d35vb5cccm4xzp.cloudfront.net/qa-tool/bx-qa-tool/bx-qa-tool.js. After all these files are loaded, the QA tool loads and the experience is rendered in preview mode.
In the client environment, the call to https://d1mj578wat5n4o.cloudfront.net/sitecore-engage-v.1.4.0.min.js loaded correctly, but the next call to https://d35vb5cccm4xzp.cloudfront.net/web-flow-libs/<clientKey>/web-version.min.js failed with a 403 forbidden response.
I tried to call the url directly and got the same 403 forbidden response.
I spent hours comparing my partner sandbox to the client environment seeing if there was anything that I could change or anything that was different between the two accounts. I could not find anything useful. I turned to the Sitecore Slack Community to ask my question. The answer came from @Derek Fahey. I had my experience in draft mode. This was the first experience I was creating in my client’s environment. He suggested that I start the experience and make it live. This causes a publish to happen. The 403 was likely caused by not having live content in the web config files. Once I did that, the https://d35vb5cccm4xzp.cloudfront.net/web-flow-libs/<clientKey>/web-version.min.js loaded correctly and I was able to preview the experience on my local site with the QA tool.
When you are setting up Personalize the first time, make sure to start/publish an experience straight away. Then you pause/complete/delete it. This will allow you to correctly preview any future experiences even in draft mode without error.
Derek also mentioned that this isn’t a problem in new tenants as they do a soft publish to ensure the config files are updated when the environment is provisioned.
]]>In many places around the world, June is considered Pride Month. We kicked off Pride Month by celebrating the launch of PRISM, Perficient’s newest ERG dedicated to creating safe spaces for understanding, education, and culture focused on respect, recognition, and learning for the LGBT+ community and allies.
PRIDE Month Realness
For our first event, we proudly launched our inaugural Perficient Ball, “10 10 10‘s – Celebrating Pride Across the World.” This event was an epic showcase of our diversity and courage, representing our unity around the globe.
Colleagues around the world celebrate pride in various ways: gathering with friends, attending marches, expressing our freedom, and sharing our support and pride with the community. Historically, the LGBT+ community has sought and created safe spaces, and one of these iconic spaces is the “Ball.”
In its beginnings, Balls were places where predominantly gay and trans people found moments of joy, embracing their identities to the fullest. In a world where they couldn’t see each other, a Ball was a space to shine, dance, and find love and security, all with glamour, glitter, and energy (think 1991’s Paris Is Burning). Today, Balls are open to the entire queer community and continue to be spaces of celebration and self-expression.
Our Event
Embracing this rich tradition, we created an event for our Perficient members around the world to celebrate together, learn, and connect. We witnessed how both the community and allies showcased their pride from their respective corners of the globe.
During our event, we aimed to crown our “Proudest Perficient PRISM Member.” We had seven finalists, guided by our charismatic host and PRISM co-chair, Avi Fuld. Each finalist shared their experiences through videography, photos, and presentations from vibrant locations such as Guadalajara, Argentina, Chicago, St. Louis, and Atlanta.
What the judges liked most during the competition was the originality, the music, our cultural diversity, the passion, and the historical touches that the competitors were able to incorporate into their presentations, and we can hear through the competition that everyone must be ready to be “Too glam to give a damn.”
We had over 50 people attend on Teams throughout the event, who kept the energy high through all participants’ presentations. In the end, the spirit of inclusivity and celebration led us to crown 3 participants as winners, and 4 runner ups. Each finalist brought unique energy, passion, and pride to the event, embodying the very essence of PRISM. By celebrating every participant, we honored the diverse stories and vibrant contributions of our community members, and we were able to donate to even more charities than initially planned.
Overall, PRISM’s first event as an official ERG was a dazzling success! PRISM is more than an ERG; it’s a community where we celebrate authenticity, inclusivity, and pride. We invite you to join us in creating safe spaces and fostering a culture of respect and learning. Let’s continue to support each other, celebrate our diversity, and shine together.
]]>Sitecore Personalize uses a combination of experiences, decision models and offers to personalize content. An experience defines a variant. The variant is used to create the UI for the experience. The decision model uses programmables and decision tables to select an offer. The variant reads data from the offer to populate the UI. By default, Sitecore Personalize expects the variant to have one user experience and for the decision model to return offers that all use the same offer template. But what if you want to have different user experiences? You could have a block of content with a title, image and cta. You could have another block of content with a title, several icons each with their own block of text. You could have yet another block of content with the image on the left and the title and description on the right. Let’s look at some ways to do this in Sitecore Personalize.
Multiple web experiences, multiple decision models, multiple offer templates.
You would create one experience, decision model and offer template per layout. If your layouts share the same data fields, you can reuse the offer template. If your layouts share the same logic, you can reuse the decision model. In this case you will use page targeting and filtering to help control where and when the experiences will be displayed on your site. Be aware that this option could have performance impacts as the number of experiences rise. Sitecore Personalize will check every experience to see if it needs to run for the current page or current user.
Pros: Easy to manage each individual layout.
Cons: The page targeting, filtering, decision models, and offers can get cumbersome and complex to manage. It is difficult to predict which experience will trigger on a given page for a given user.
One web experience, one decision model, one offer template.
You would create one web experience with multiple layouts defined in the html. Use if statements to decide which layout is visible based on a variable in the api. Include a number field in the offer template that indicates which layout to use. Add fields to the offer template to support all the different layouts. Don’t add fields to the offer template that you don’t need and try to reuse fields across layouts by using generic labels. You might create a help document for content authors to know which fields are used by which layout. Keep in mind that you cannot reorder fields on an offer template and you can only add new fields at the end of the list. When you create an offer, all fields from the offer template must be filled out to save the offer (you can use NA on fields not required by the specific layout).
Pros: Only one experience to manage. Only one decision table to manage.
Cons: Having multiple layouts in one experience can get a little confusing to preview. Creating an offer requires knowledge of how the fields are used in each layout.
One web experience, one decision model, multiple offer templates.
This is similar to option 2 except that you would create one offer template per layout. The fields can be labeled specifically how they will be used in a single layout. This makes it easier for the content authors to create an offer based on the correct offer template for the target layout. The decision model gets more complicated as you add more layouts. You add a decision table for each layout/offer template. You must assign your inputs to each decision table. The content authors are able to assign the correct offer to the correct layout.
Be aware that this option could have performance impacts as the programmables are evaluated for each decision table on the canvas.
Pros: Only one experience to manage. Individual offers are easier to manage.
Cons: The decision model is harder to manage as the number of layouts grows. Each programmable is evaluated once per decision table.
One full stack experience, one decision model, one offer template.
One full stack experience, one decision model, multiple offer templates.
These two options are the same as option 3 and 4 except they use a full stack experience instead of a web experience. This means you will call the personalize api manually. This can be done either server-side or client-side. You will use the data returned from the api to populate the UI.
Pros: Complete control of UX.
Cons: You must call the personalize api manually and handle the response to populate the UI. Requires developers to make the api calls as well as to make changes to the UX.
You can bend the rules of Sitecore Personalize to allow multiple layouts. Consider the pros and cons of each solution and pick the option that is the easiest to manage while keeping the highest performance for your situation.
Shoutout to Megan Jensen for the fun visualization graphics!
]]>Many people are starting to moving away from Docker Desktop. It is important to remember that Docker Desktop is not Docker! Docker is a standalone tool that allows you to run containers. Docker Desktop is a separate tool that gives you some information about your images and containers in a nice GUI. In this article, I’ll give you a few tips for using Docker without Docker Desktop and show you how to use other tools to get the same information you can get from Docker Desktop.
If you haven’t done the manual install of Docker yet, check out Vikrant Punwatkar’s blog post. For the rest of this article, I’ll use the docker install path c:\docker as suggested.
Restart your machine! This will help clear up potential issues when installing Docker manually.
You can use a json file to change the behavior of the docker engine
I wanted to keep everything nicely contained in the c:\docker folder. But I discovered the compose plugin must be placed in C:\Program Files\docker\cli-plugins.
You can verify the compose plugin is installed at the correct location by running “docker info”.
Compose is listed as a plugin with the correct path
You can add optional flags to the dockerd command to register the service. This command mimics how docker desktop registers the docker service.
dockerd --register-service --service-name docker --group docker-users --config-file C:\docker\config\windows-daemon.json
You will want to periodically check the docker download page for new version of docker. Follow these steps to upgrade to the new version.
Like Vikrant mentioned in his post, you can use Visual Studio and VSCode to manage your containers. If you want a GUI experience that is close to Docker Desktop, check out one of these tools below. Keep in mind that these tools do not include the docker exe file. You still have to install docker manually.
The containers tab of the Rancher Desktop ui
The containers tab of the Podman Desktop ui
You can of course use docker without any GUI tools through the command line. Here are some common things you can do with a docker gui and the equivalent command with the cli.
If you are no longer using Docker Desktop, there are still plenty of ways to use Docker. I hope this article helps you find the way that works best for you!
]]>Welcome back to getting to know Sitecore Search. Sitecore Search is an evolving product. Products are moving away from large monolithic products with long upgrade/release cycles to smaller composable products with shorter agile upgrade/release cycles. In this post, I’ll revisit several of my previous posts and make updates based on changes in the product and what I’ve learned over time.
Sitecore Search is part of the composable ecosystem of products. The URL has changed from the previous Reflection URL (https://cec.rfksrv.com/home) to the new Sitecore Cloud url (https://cec.sitecorecloud.io/home).
The Sitecore Search UI (aka CEC) has stayed mostly the same. It is now branded with the Sitecore Search logo instead of the Sitecore logo. The catalog has been renamed “content collection”. Catalog was a holdover name from the evolution from Discover which is more product-focused and made more sense in that context. The sources have been moved to the left sidebar instead of hiding under Administration. It’s a small change but makes a lot of sense to me. Get users where they want to go quicker. It still requires the TechAdmin or Admin role to access.
I had previously mentioned that a request trigger will only crawl the one URL specified. Also, I thought that was strange that a crawler would not actually crawl a site to find other pages linked from the given page. I accidentally had my max depth set at 0 and only got one document. Be sure to set your max depth and max urls on your web crawler settings to allow the crawler to discover pages.
Conversely, if you are using a sitemap trigger, you may want to set your max depth to 0 so that only the pages in the sitemap are indexed. If you want the crawler to crawl the pages in the sitemap for other pages that might not be listed in the sitemap, increase your max depth.
As mentioned in this article, there are three types of document extractors. CSS, Xpath, and JS. A document extractor can have multiple extractors. Each extractor can set the type and list of URLs to match. This allows you to tag sections of your website differently. The CSS and Xpath selectors offer quick and easy access to your content, but they are less flexible and less powerful.
While you can change extractor types, it is likely best to use the JS extractor as your default. This allows you to add logic and do complex operations as your needs change. I’ll cover advanced document extractors in a future post.
It is nice to see that the document extractor has been updated to give feedback on errors as you type.
Since I started this series, the official documentation for Sitecore Search has been released. It includes a developer guide as well as a Sdk guide for React. This new documentation does a great job of walking you through setting up your project to use the react SDK, using the CLI to create components, and how to style your components.
The react SDK website is also continuously being updated. When I started, the SDK was in version 1.0-alpha. It upgraded to version 2 along the way. While the old versions still exist, you should always use the latest version.
It’s easy to add the react SDK to your project
If you’ve installed an old version in the past, make sure to use the latest version
I discovered the Sitecore Search CLI by following the documentation for Sitecore Discover and guessing that the same existed for Search. Several people in the Sitecore Slack Search channel pointed me to the npm packages before the documentation was updated. The Sitecore Search CLI makes it fast and easy to add components to your React application.
It’s easy to add the Sitecore Search CLI to your project
If you’ve installed an old version in the past, make sure to use the latest version
The search sdk has updated the installation instructions. Look at the cli tab under installation for any widget. There are two dropdowns on the right that let you change cli settings to get the desired component. You can choose between typescript and javascript as well as several styling options.
Storybook cli options for style type
Sitecore Search CLI output for the new widget
When I wrote this article, I had very little React experience. I had not used styled components before. I had created widgets using the “styled” flag without giving it much thought. After this article was published, I chatted with Pablo Barrenechea from Sitecore. He showed me how to style the components correctly.
If you create widgets with the “styled” option you will notice several things:
To style components, find the matching component name in the styled.js file and modify the CSS. Because the CSS is wrapped in the backtick operator, you won’t get typeahead and autocomplete (in VSCode), so watch for typos. Styled components create unique class names for your styles, which you see when you inspect the DOM of the rendered page. You do not have to inspect the dom and find the randomly generated class names to style your app!
If you create widgets with the “CSS” option you will notice several things:
To style components, find the matching class name in the styles.css file and modify the css as usual.
Again, being new to React, I did not understand the defaultSortType property. I mentioned that I changed the value of the defaultSortType in the component file. But now I know it is a prop and you can pass it in when you use the component. You can pass in the other props for defaultPage, defaultKeyphrase, and defaultItemsPerPage as well.
<SrwiJsStyled rfkId=”rfkid_7″ defaultSortType=”best_match” defaultItemsPerPage={24} />
I have learned a lot about Sitecore Search and React since I started this blog series. In the beginning, I wanted to jump head-first into Sitecore Search. Looking back, some of the places I stumbled upon seem obvious now. I could have saved myself a little time by learning some of the basics of React and Styled Components first. But it’s all part of the journey!
If you have questions about Sitecore Search or Sitecore in general, you should join Sitecore Slack! Interact with other community members as well as the product team behind Sitecore Search. Get direct answers to your specific questions.
Follow me on LinkedIn to get notifications as new articles are posted.
]]>