Configure zones on your channel

Set up zones to display the personalized content or recommendations on your channel.

Before you begin

📘

Note:

The code snippets, function names, method names, variables provided are for guidance only. The channel developer can modify them as per their channel-specific implementation. As a best practice, validate the library updates in a non-Production environment first.

Stable version (v.1.5.0)

  1. In the MPA page that has the zones to be personalized, create a <script> tag. You can add the <script> tag either to the HEAD tag or in the BODY tag of the MPA page.
  2. In the script tag, create an object personalizationObject to load the Personalization library. Exchange creates the Acoustic object.
const personalizationObject = acoustic.personalization.JsWRTP.create();
  1. Write a function displayContent that takes in two parameters:
    • ContentID = ID of the personalized content (for example, an image) that will be displayed.
    • domOutlet = Outlet ID (usually the div id) of the page that has the registered zone.
  2. In the displayContent function, add IF-ELSE blocks. These blocks contain the code to render personalized content and the default content. The default content is used to display if Personalization fails. For example,
function displayContent(contentId, domOutlet) { if (contentId == 'DCIDNF404') { //Add rendering logic code to display the default content domOutlet.style.opacity = 1; } else { //Add rendering logic code to display the personalized content domOutlet.style.opacity = 1; } }
  • The error code DCIDNF404 is returned when no published rules are available. The error also occurs when none of the published rules match the visitor behavior on the channel. In such a case, Personalization does not return any personalized content. The channel must handle this scenario by specifying the default content to be displayed. For more information about the error codes, see Personalization Library response codes.
  • The code domOutlet.style.opacity = 1; is for handling the content flicker on the channel. You can choose to handle the content flicker using a different approach. For more information, see Handling the content flicker.
  • Write the function processContent. This function processes the zoneID and OutletID parameters declared earlier.
function processContent(zoneId, outletId) { const outletArea = personalizationObject.getZoneArea(outletId); let contentId = personalizationObject.getContentId(zoneId); displayContent(contentId, outletArea); }
  1. Add the OnReady function as shown below.
personalizationObject.onReady(()=>{ // Repeat this line of code for each new zone to be personalized. processContent("ZONE ID", "OUTLET"); });
  • Replace ZONE ID with the registered zone ID.
  • Replace OUTLET with the outlet ID (usually the div id) of the page with the registered zone.

Your complete code structure would look like the following code snippet.

<script type="text/javascript"> function init() { if (acoustic != undefined || acoustic != {}) { const personalizationObject = acoustic.personalization.JsWRTP.create(); function displayContent(contentId, domOutlet) { console.log('ContentId in HTML file:', contentId); if (contentId == 'DCIDNF404') { //Add rendering logic code to display the default content domOutlet.style.opacity = 1; } else { //Add rendering logic code to display the personalized content domOutlet.style.opacity = 1; } } function processContent(zoneId, outletId) { const outletArea = personalizationObject.getZoneArea(outletId); let contentId = personalizationObject.getContentId(zoneId); displayContent(contentId, outletArea); } personalizationObject.onReady(()=>{ processContent("ZONE ID", "OUTLET"); }); } else { console.log("Error in loading the personalization library."); } } window.onload = init; </script>

Latest version
You can use this procedure for Personalization library versions 2.0.0, 2.1.0, and 2.2.0.

  1. Open the HTML webpage that contains the zone you want to be personalized. Add a <script> tag. You can add this tag either in HEAD or BODY of the HTML page. Adding the script tag allows you to run business logic in your HTML pages.
<script type="text/javascript"> //Step 2 goes here </script>
  1. Within this script tag, initialize the Personalization library. You do this to import the library objects.
var init = (function () { //Add step 3 here });
  1. Add a check to ensure that the library is loaded and you can access the Acoustic object. Otherwise, you will see an error message in the console log.

📘

Note:

If you cannot retrieve the object, it means the library is not installed correctly. In this case, perform the steps to install the Personalization library.

if (acoustic != undefined || acoustic != {}) { //Add steps 4 to 8 here } else { console.log("Error in loading Personalization Library."); }
  1. Create an object personalizationObject to access the library functions.
var personalizationObject = acoustic.personalization.PersonalizationLibrary.create();
  1. Create a DOM element validator. This validator checks whether the zone to be personalized exists on the HTML page. If the zone is not a valid HTML element, you will see an error message.
var validateDOMElement = function (outlet) { var outletDiv = document.getElementById(outlet); if (!(outletDiv instanceof Node)) { console.log(outlet, " is not a valid HTML element."); return null; } return outletDiv; };
  1. Add a SWITCH case handler. In this handler, you add the processing logic for various content types. The following content types are currently supported:
var personalizationHandler = function(result, targetArea) { switch(result.type) { //Use to display product recommendations on the zone case "recommendation": displayRecommendations(result, targetArea); break; //Use to display personalized content from the specified web URL case "custom-url": displayCustomUrl(result, targetArea); break; //Use to fetch personalized content from the specified web page case "custom-html": displayCustomHtml(result, targetArea); break; //Use to fetch personalized content as HTML from Acoustic Content case "wch-url": displayWchUrl(result, targetArea); break; //Use to fetch personalized content as a URL from Acoustic Content case "wch-html": displayWchHtml(result, targetArea); break; //Use to display the default content case "": displayDefaultContent(result, targetArea); break; } }

Helper functions to support content types:
The SWITCH case handler calls the relevant helper functions that support content types. The supported content types are default content, HTML, URL, and recommendations. For reference, the following code snippet provides the definitions of these helper functions. These helper functions are located inside the personalizationHandler() function.

var displayDefaultContent = function (result, targetArea) { // Display the default content targetArea.style.opacity = 1; } var displayCustomUrl = function (content, targetArea) { var contentId = content.value if (contentId && contentId !== 'CONNF404' && targetArea) { // Display the personalized content targetArea.style.opacity = 1; } else { displayDefaultContent(content, targetArea); } } var displayWchUrl = function (content, targetArea) { var contentId = content.value if (contentId && contentId !== 'CONNF404' && targetArea) { // Display the personalized content targetArea.style.opacity = 1; } else { displayDefaultContent(content, targetArea); } } var displayCustomHtml = function (content, targetArea) { var contentId = content.value if (contentId && contentId !== 'CONNF404' && targetArea) { // Display the personalized content targetArea.style.opacity = 1; } else { displayDefaultContent(content, targetArea); } } var displayWchHtml = function (content, targetArea) { var contentId = content.value if (contentId && contentId !== 'CONNF404' && targetArea) { // Display the personalized content targetArea.style.opacity = 1; } else { displayDefaultContent(content, targetArea); } } var displayRecommendations = function (products, targetArea) { var recommendations = products.value; if (recommendations && recommendations !== 'CONNF404' && targetArea) { // Display the personalized recommendations } else { // Display the default recommendations displayDefaultContent(products, targetArea); } }
  1. Add the onReady callback function. This function ensures that the library has loaded the required files for processing.
personalizationObject.onReady(function() { // Add step 8 here });
  1. Configure the personalized zones. You do this to see the personalized content on the zones. You can use any of the two approaches described here.

Approach 1: Using custom attributes
Use this approach to access the defined values from the HTML dynamically. This approach requires you to make changes to the div tag of the zone.
In the onReady callback, specify the attributes and their values to be fetched dynamically.

personalizationObject.onReady(function(){ var zones = document.querySelectorAll('[custom-pzn]'); zones.forEach(function(value) { var zoneObj = { "zoneId": value.getAttribute('custom-pzn-zone-reg-id'), "targetArea": value.getAttribute('custom-pzn-target-area'), "num": value.getAttribute('custom-pzn-product-number') }; var validElement = validateDOMElement(zoneObj.targetArea) if(validElement) { personalizationObject.getContent(zoneObj) .then(function(result) { personalizationHandler(result, validElement) }); } }); });

Changes to HTML file using Approach 1: Open the HTML file of your MPA zone. Add the following snippet to it.

<div> <div id="<ZONE_ID>" wrtp-recommended-zone="<ZONE_ID>" custom-pzn custom-pzn-zone-reg-id="<ZONE_ID>" custom-pzn-target-area="<ZONE_ID>[CAN_BE_SAME_AS_<ZONE_ID>]" custom-pzn-product-number="<NUMBER_OF_PRODUCTS_REQUIRED>[OPTIONAL]"> </div> </div>
  • ZONE ID – Replace with the registered zone ID.
  • ZONE_AREA – Replace with the outlet ID (usually the div id) of the page that has the registered zone.
  • NUMBER_OF_PRODUCTS_REQUIRED – Replace with the maximum number of recommended products to be displayed on the zone. For example: "10". This is an optional parameter.

Approach 2: Without using custom attributes
Use this approach when you want to make minimal changes to your website's div tags. In this case, Personalization business logic manages the complete processing.
Use this approach to access the values from the business logic.

personalizationObject.onReady(function(){ var zones = [ { "zoneId": "ZONE_ID_1", "targetArea": "ELEMENT_ID_2", "num": "NUMBER_OF_PRODUCTS_[OPTIONAL]" }, { "zoneId": "ZONE_ID_2", "targetArea": "ELEMENT_ID_2", "num": "NUMBER_OF_PRODUCTS_[OPTIONAL]" }, ] zones.forEach(function(zoneObj) { var validElement = validateDOMElement(zoneObj.targetArea) if(validElement) { personalizationObject.getContent(zoneObj) .then(function(result){ personalizationHandler(result, validElement) }); } }); });

Changes HTML file using Approach 2: Open the HTML file of your MPA zone. Add the following snippet to it.

<div> <div id="ZONE_ID" wrtp-recommended-zone="ZONE_ID"> <!-- Replace ZONE_ID with the registered zone ID--> </div> </div>

Example code
Your complete code would look similar to the following code snippet. This example uses Approach 1 for configuring the personalized zones.

// Step 1 <script type="text/javascript"> // Step 2 var init = (function () { // Step 3 // get the personalization object if (acoustic != undefined || acoustic != {}) { // Step 4 // access the personalization object var personalizationObject = acoustic.personalization.PersonalizationLibrary.create(); // Step 5 // Create a DOM Element validator for the identified zones in the client application var validateDOMElement = function (outlet) { var outletDiv = document.getElementById(outlet); if (!(outletDiv instanceof Node)) { console.log(outlet, " is not a valid HTML element."); return null; } return outletDiv; }; // Helper functions for personalizationHandler var displayDefaultContent = function (result, targetArea) { // Display the default content targetArea.style.opacity = 1; } var displayCustomUrl = function (content, targetArea) { var contentId = content.value if (contentId && contentId !== 'CONNF404' && targetArea) { // Display the personalized content targetArea.style.opacity = 1; } else { displayDefaultContent(content, targetArea); } } var displayWchUrl = function (content, targetArea) { var contentId = content.value if (contentId && contentId !== 'CONNF404' && targetArea) { // Display the personalized content targetArea.style.opacity = 1; } else { displayDefaultContent(content, targetArea); } } var displayCustomHtml = function (content, targetArea) { var contentId = content.value if (contentId && contentId !== 'CONNF404' && targetArea) { // Display the personalized content targetArea.style.opacity = 1; } else { displayDefaultContent(content, targetArea); } } var displayWchHtml = function (content, targetArea) { var contentId = content.value if (contentId && contentId !== 'CONNF404' && targetArea) { // Display the personalized content targetArea.style.opacity = 1; } else { displayDefaultContent(content, targetArea); } } var displayRecommendations = function (products, targetArea) { var recommendations = products.value; if (recommendations && recommendations !== 'CONNF404' && targetArea) { // Display the personalized recommendations } else { // Display the default recommendations displayDefaultContent(products, targetArea); } } // Step 6 // A handler at the client side to process the results var personalizationHandler = function(result, targetArea) { switch(result.type) { case "recommendation": displayRecommendations(result, targetArea); break; case "custom-url": displayCustomUrl(result, targetArea); break; case "custom-html": displayCustomHtml(result, targetArea); break; case "wch-url": displayWchUrl(result, targetArea); break; case "wch-html": displayWchHtml(result, targetArea); break; case "": displayDefaultContent(result, targetArea); break; } } // Step 7 // Configure personalization personalizationObject.onReady(function(){ // Step 8 configure zones (Approach 1) var zones = document.querySelectorAll('[custom-pzn]'); zones.forEach(function(value) { var zoneObj = { "zoneId": value.getAttribute('custom-pzn-zone-reg-id'), "targetArea": value.getAttribute('custom-pzn-target-area'), "num": value.getAttribute('custom-pzn-product-number') }; var validElement = validateDOMElement(zoneObj.targetArea) if(validElement) { personalizationObject.getContent(zoneObj) .then(function(result) { personalizationHandler(result, validElement) }); //Optional code to capture click events personalizationObject.collectBehavior("ELEMENTID","EVENT ","ZONEID"); } }); }); } else { console.log("Error in loading the Personalization library."); } }); </script>

Stable version

Complete the following step only once for your channel. Step (2) onwards must be done for each zone that you want to personalize.

  1. Add the following imports in the app.module.ts file or the root module file.
import {PersonalizationModule} from '@acoustic/personalization';

Add the PersonalizationModule.forRoot({}) in the imports array of @NgModule().

@NgModule({ imports: [ ... PersonalizationModule.forRoot({}) ... ], })
  1. Identify the zones on your channel that you want to personalize.
  2. Add the following imports in the component file to which the identified zone belongs.
import {of, throwError, concat} from 'rxjs'; import {map, catchError } from 'rxjs/operators'; import {NgPersonalization} from '@acoustic/personalization';
  1. Add the following code to import and inject the NgPersonalization and other dependencies. The NgPersonalization and dependencies are injected in the constructor of the component.
constructor(private personalizationService: NgPersonalization) {}
  1. Create a variable resultObservable$. The variable subscribes to the observable that is returned from the library. Copy the following code snippet and paste it in the ngOnInit() function.
<script type="text/javascript"> function init() { if (acoustic != undefined || acoustic != {}) { const personalizationObject = acoustic.personalization.JsWRTP.create(); function displayContent(contentId, domOutlet) { console.log('ContentId in HTML file:', contentId); if (contentId == 'DCIDNF404') { //Add rendering logic code to display the default content domOutlet.style.opacity = 1; } else { //Add rendering logic code to display the personalized content domOutlet.style.opacity = 1; } } function processContent(zoneId, outletId) { const outletArea = personalizationObject.getZoneArea(outletId); let contentId = personalizationObject.getContentId(zoneId); displayContent(contentId, outletArea); } personalizationObject.onReady(()=>{ processContent("ZONE ID", "OUTLET"); }); } else { console.log("Error in loading the personalization library."); } } window.onload = init; </script>

In the code snippet:

  • ZONE ID – Replace as a parameter. For more information about the zone ID, see Registering a zone.
  • DEFAULTCONTENT – The default content that you want to display on the channel. The default content displays if no rules match the user behavior.
  • The error code DCIDNF404 is returned when no published rules are available. The error also occurs when none of the published rules match the visitor behavior on the channel. In such a case, Personalization does not return any personalized content. The channel must specify the default content to be displayed. For more information about the error codes, see Library response codes.

If the zones to personalize are in the same component, include them in the same onReady function. If the zones to personalize are in different components, then create separate functions.

  1. Repeat the steps for each zone that you want to personalize
  2. Render the content returned by Acoustic Personalization.

Example code:

this.personalizationService.onReady(()=>{ this.resultWelcomeBanner$ = this.personalizationService.getContentId('WelcomeBannerZone') .pipe( map(id => id === 'DCIDNF404' ? '906bb0b5-bf17-45c5-89e7-ce0c58300a03' : id), catchError(error => { console.log('Error', 'Rule not matched from SPA'); return concat(of('cddcefc7-6227-483b-8fd7-63a45c6fd244'), throwError(error)); }) ); this.resultFeature$ = this.personalizationService.getContentId('FeatureLayoutZone') .pipe( map(contentId => contentId === 'DCIDNF404' ? 'cab6e657-bee0-4635-b9a4-d76ea3292483' : contentId), catchError(error => { console.log('Error', 'Rule not matched from SPA'); return concat(of('cab6e657-bee0-4635-b9a4-d76ea3292483'), throwError(error)); }) ); });

Latest version
You can use this procedure for the personalization library versions 2.0.0, 2.1.0, and 2.2.0.

Perform the following steps in the file app.module.ts

  1. Add the following code to import the Personalization Library.
import { PersonalizationLibrary } from @acoustic/personalization”;
  1. Initialize the PZN library inside the constructor of the application's RootModule.
export class AppModule { constructor() { PersonalizationLibrary.create(); } }
  1. Add the imported personalization object PersonalizationLibrary into the provider's array. This object enables the personalization service to be shared and used across the client application.
providers: [ PersonalizationLibrary . . . ]

Perform the following steps to target.component.ts
Identify the component where the personalization/ recommendation is to be added. Then make the following changes:

  1. Add the following import to use the personalization object as a service in the client application's target component.
import {PersonalizationLibrary} from @acoustic/personalization’;
  1. Add the imported member into the constructor.
constructor(private personalizationObject: PersonalizationLibrary) {}
  1. Configure the zone. The switch case shown below illustrates the processing for various content types. The following content types are currently supported:
    • recommendation
    • custom-url
    • custom-html
    • wch-html
    • wch-url
    • "" – To be used when the content returned is a default content.
      If needed, you can add the processing for other content types as per your requirement.
function personalizationHandler(result) { switch(result.type) { case "recommendation": return displayRecommendations(result); case "custom-url": return displayCustomUrl(result); case "custom-html": return displayCustomHtml(result); case "wch-url": return displayWchUrl(result); case "wch-html": return displayWchHtml(result); case "": return displayDefaultContent(result); } }

Definitions of the helper functions
The following code snippet provides the definitions of helper functions inside the personalizationHandler() function.

displayDefaultContent(content) { // return the default content } function displayDefaultHTMLContent(content) { // return the default HTML content } function displayCustomHtml(content) { let contentId = content.value if (contentId && contentId !== 'CONNF404') { // return the personalized html content } else { displayDefaultHTMLContent(content); } } function displayWchHtml(content) { let contentId = content.value if (contentId && contentId !== 'CONNF404') { // return the personalized html content } else { displayDefaultHTMLContent(content); } } function displayCustomUrl(content) { let contentId = content.value; if (contentId && contentId !== "CONNF404") { // return the personalized content } else { // return the default content displayDefaultContent(content); } } function displayWchUrl(content) { let contentId = content.value; if (contentId && contentId !== "CONNF404") { // return the personalized content } else { // return the default content displayDefaultContent(content); } } function displayRecommendations(products) { let recommendations = products.value; if (recommendations && recommendations !== "CONNF404") { // return the personalized recommendations } else { // return the default recommendations return displayDefaultContent(products); } }

Configure the personalized zones.

this.personalizationObject.onReady(()=>{ this.personalizationObject.getContent({ zoneId:<ZoneRegId>, num: <numberofproducts>[OPTIONAL]}) .then( result => { this.VARIABLE_NAME = personalizationHandler(result); // VARIBLE_NAME can be used to display the contents } ) });

Changes to HTML file.

<div id=<ZoneRegId>” wrtp-recommended-zone=”<ZoneRegId>”> <div *ngIf=<VARIABLE_NAME>”></div> // Make use of this variable to display and render the contents </div>

In the code snippet:

  • ZONE ID – Replace with the registered ID of the zone you want to personalize. For more information about the zone ID, see Registering a zone.
  • DEFAULTCONTENT – The default content that you want to display on the channel. The default content displays if no rules match the user behavior.
  • The error code DCIDNF404 is returned when no published rules are available. The error also occurs when none of the published rules match the visitor behavior on the channel. In such a case, Personalization does not return any personalized content. The channel must specify the default content to be displayed. For more information about the error codes, see Library response codes.
    If the zones to personalize are in the same component, include them in the same onReady function. If the zones to personalize are in different components, then create separate functions.

Stable version (v1.5.0)

To configure the zones of your React-based SPA, complete these steps:

  1. In the identified zone's component file, add the following before the render() function.
constructor () { super(); this.WRTP = acoustic.personalization.JsWRTP.create(); this.state = { contentOne: '' }; } componentDidMount () { this._isMounted = true; this.zoneId = "ID of zone to be personalized"; this._isMounted && this.WRTP.onReady(()=>{ let contentId = this.WRTP.getContentId(this.zoneId); this._isMounted && this.setState({ contentOne: contentId, }); }); } componentWillUnmount () { this._isMounted = false; }
  1. Integrate with your rendering logic. The rendering logic should return a valid HTML div similar to the code snippet below.
return ( <div id="ZONEID" key={ this.state.contentOne !== 'DCIDNF404' ? this.state.contentOne : defaultContent }> {/*Add the code for rendering logic by setting HTML5 element attribute with contentId*/} <img /*HTML5 element attribute, eg:*/ src = { this.state.contentOne !== 'DCIDNF404' ? this.state.contentOne : defaultContent } /> </div> );

In the code snippet, replace the ZONEID with the ID of the zone to be personalized.

Latest version
You can use this procedure for personalization library versions 2.0.0., 2.1.0, and 2.2.0.

To configure the zones of your React SPA, complete these steps:

Update the RootComponent.jsx

  1. Add the following code to import the library object into the client application.
import { PersonalizationLibrary } from "@acoustic/personalization";
  1. Export the PersonalizationContext to use it across the website.
export const PersonalizationContext = React.createContext();
  1. Initialize the personalizationObject inside the RootClass of the application.
const personalizationObject = PersonalizationLibrary.create();
  1. Wrap the application router with the provider of the PersonalizationContext. The personalization object data can then be shared across the website.
<PersonalizationContext.Provider value={ personalizationObject }></PersonalizationContext.Provider>

The completed Root component should look similar to the one shown here.

class RootClass extends React.Component { const personalizationObject = PersonalizationLibrary.create(); render() { return ( <PersonalizationContext.Provider value={ personalizationObject }> <Router > <Switch> <Route></Route> . . <Route></Route> </Switch> </Router> </PersonalizationContext.Provider> ); }

Update TargetComponent.jsx

  1. Import the PersonalizationContext from the app/root module of the application.
import { PersonalizationContext } from "<path to the app/root module>";
  1. At the end of the class file, set the target component's context type as Personalization context. You can then use the personalization functionalities in the target component.
TargetComponentClass.contextType = PersonalizationContext;
  1. Configure the content personalization. The switch case shown below illustrates the processing for various content types. The following content types are currently supported:
    • recommendation
    • custom-url
    • custom-html
    • wch-html
    • wch-url
    • "" – To be used when the content returned is a default content.
      If needed, you can add the processing for other content types as per your requirement.
componentDidMount() { this.personalizationObject = this.context; function personalizationHandler(result) { switch(result.type) { case "recommendation": return displayRecommendations(result); case "custom-url": return displayCustomUrl(result); case "custom-html": return displayCustomHtml(result); case "wch-url": return displayWchUrl(result); case "wch-html": return displayWchHtml(result); case "": return displayDefaultContent(result); } }

Definitions of the helper functions
The following code snippet provides the definitions of helper functions inside the personalizationHandler() function.

function displayDefaultContent(content) { // return the default content } function displayDefaultHTMLContent(content) { // return the default HTML content } function displayCustomHtml(content) { let contentId = content.value if (contentId && contentId !== 'CONNF404') { // return the personalized html content } else { displayDefaultHTMLContent(content); } } function displayWchHtml(content) { let contentId = content.value if (contentId && contentId !== 'CONNF404') { // return the personalized html content } else { displayDefaultHTMLContent(content); } } function displayCustomUrl(content) { let contentId = content.value; if (contentId && contentId !== "CONNF404") { // return the personalized content } else { // return the default content displayDefaultContent(content); } } function displayWchUrl(content) { let contentId = content.value; if (contentId && contentId !== "CONNF404") { // return the personalized content } else { // return the default content displayDefaultContent(content); } } function displayRecommendations(products) { let recommendations = products.value; if (recommendations && recommendations !== "CONNF404") { // return the personalized recommendations } else { // return the default recommendations return displayDefaultContent(products); } }

Configure the personalized zones.

this.personalizationObject.onReady(() => { this.personalizationObject.getContent({zoneId : '<ZoneRegId>', num: <numberofproducts>[OPTIONAL]}) .then(result =>{ this.setState({ <VARIABLE_NAME>: personalizationHandler(result) // Replace <VARIABLE_NAME> with personalized content. }); }); });

Use the <VARIABLE_NAME> to render the personalized content. If <VARIABLE_NAME> is 'CONNF404' then show the default content. Otherwise, display the personalized content or recommendations.