Personalization is one of the major headless scenarios that any Hybrid Headless CMS Platform should support. Marketers want to bring personalized experiences to any channel, whether it is web, mobile device, social, email or chat. They want to leverage the accumulated data from the web and other channels, and manage personalized content for their website to make it instantly available to the channels that their audience engages with the most.
Now that you know how to consume and create content with the OData services and how to authenticate the users of your application, let’s continue with this important part of the customer experience.
Note: This is the fourth post from the series about building an Angular application with Sitefinity’s headless capabilities. You can check part 1, part 2 and part 3 here.
In this blog post, we will talk about personalization and how to show personalized content in your headless app using Sitefinity OData services. We will also explore how to work with the Layout service API to render Sitefinity page content and structure outside Sitefinity. This post is the fourth part of the series about building Angular applications with Sitefinity’s headless capabilities and will build on top of the sample (part 1, part 2, part 3). You can find the sample here.
What is personalization?
Personalization consists of tailoring a service or a product to accommodate specific individuals and their needs. Sitefinity helps you deliver different versions of content, page assets, and pages to different types of audiences, called user segments. You define segments based on a wide range of user characteristics and data that you can combine in rules and conditions. Learn more about personalization in Sitefinity in the documentation.
What is the personalization in this sample?
In Sitefinity Quantum (Sitefinity Sandboxes), there is a personalized page called Lading page. It consists of several content blocks. Five of these are personalized, based on a segment called Potential clients. This means that when a potential client hits the page, the personalized content blocks will display different, specially prepared content for these types of clients.
An example scenario for this personalization is that you might want to show one content for users that are registered (existing customers), and different content for those who don’t have an account yet and are considered potential clients. Another example usage would be targeting clients, coming from different channels—websites, social media, applications, etc.
How is this personalization achieved?
In the Quantum sandbox under Marketing -> Personalization, you will see the Potential clients segment. If you open it, you will notice that it applies to users who visit the page through a specific URL (one that includes a query parameter url_campaign with value social_media). Personalization is activated only when this specific URL is hit. You could even test that yourself by opening the Landing page in the browser and adding ?url_campaign=social-media to the end of its URL. Doing this will change the content of the five content blocks on the page.
So, how do we use this personalization in an Angular application?
We do that by taking advantage of the Layout service API, which returns the content and the layout of Sitefinity pages and allows you to do your own frontend rendering of each page. Some more information about it can be found here. You can also check an article in our documentation with more information on how to use the Layout service API in a personalization scenario.
Let’s set it up in our sample
To keep the code more organized, we’ve created a new module called LayoutRendererModule. The idea is to use the Layout service API to visualize Landing page in our application. Therefore, we’ve also created a new routing path in the app, called landing-page. When this route is hit, the RootComponent is initialized, which renders the landing page for us.
You’ve probably noticed by now that the design of the layout page is different from the design of the Quantum headless app. So, to add specific styles for this page only, we add them in the stylesUrls property of the component decorator. This ensures that none of these styles will be loaded when accessing other routes.
What happens when you open landing-page in the app?
We subscribe to the ArticatedRoute URL and get the URL of the requested page. We then pass it to the PageContentService.
The PageContentService handles getting the page and its content through the Layout service API. We first get the requested page, then we check the context for lazy components. Lazy components are component that need to be loaded on demand, which in this case are all personalized widgets on the page. If there are personalized widgets, we make another call to the API for their lazy loaded/personalized versions.
The get method of the PageContentService returns several things of importance for us:
- site culture
- siteId
- content of the page
In the template of the RootComponent we pass all these to the ComponentWrapper directive, which processes them and visualizes each content from the page. It is responsible for assigning a proper Angular component to each content object that is returned from the service (which is the content of each widget on the Landing page). These Angular components are used to visualize this content, similar to the MVC widgets, but in the context of our Angular app.
In our case, the page consists of content blocks and grid/layout widgets. That’s why we have two components, corresponding to each one of these content types—ContentBlockComponent and LayoutComponent. The TYPESMAP maps each content object returned by the service to the component, which will visualize it. Once we have the proper visualization component we set its properties, create it and inject it on the page using the resolveComponentFactory method.
What’s specific about the Angular components?
The content block component is simply a div in which we render the content, and we also pass the css wrapper classes coming from the content block widget in Sitefinity. If the content block we’re visualizing is a shared one, we make an additional call to the OData services for the shared content.
The Layout component is like grid widgets in Sitefinity: it serves as a placeholder for other widgets. It can be rendered as a bootstrap row with columns and as a bootstrap container, depending on the content model properties returned from the layout service.
Now if you open Landing page in the app, you will see that the rendered html is almost identical to the html of the Sitefinity Landing page and the two pages look identical. That demonstrates the power of the Layout service API, which makes it very easy to display Sitefinity pages in SPA applications, preserving the structure of the page and its look.
Where does the personalization come along?
Personalized widgets are served as lazy loaded widgets, as mentioned earlier. To get the personalized version of a content block we subscribe to the receivedContent$ subject of the PageContentService. It nexts each lazy content from the page one by one. To get the lazy content/personalized version that corresponds to the component we are currently visualizing with ComponentWrapper, we compare the Id of the lazy loaded version to the Id of the component, and if they match, we copy the properties of the lazy loaded version to the component on the page. In short, we replace the standard version of the component with the personalized one if it exists.
How do we see this in action?
There is a new Landing page link in the navigation of the app. Once you click it you will be redirected to the default version of the Landing page. Simply add ?utmcampaign=social_media to the URL and you will notice how parts of the page get replaced with different ones, exactly like with the MVC page.
We hope you found this tutorial, as well as our previous three tutorials, useful. We encourage any developer curious about building an Angular app to read all four (ICYMI: links to part 1, part 2 and part 3).
If you have any questions, please drop us a line in the comments below. If you're new to Sitefinity, you can learn more here or jump right in and start your free 30-day trial today. We also have the headless topic covered in our free Foundations of Sitefinity Development course, so don’t hesitate to check it out.
Zheyna Peleva
Jen Peleva was a Principal frontend developer for the Sitefinity CMS.