Announcement: You can find the guides for Commerce 7.5 and later on the new Elastic Path Documentation site. This Developer Center contains the guides for Commerce 6.13.0 through 7.4.1.Visit new site

This version of Elastic Path Commerce is no longer supported or maintained. To upgrade to the latest version, contact your Elastic Path representative.

Customizing Personalization

Customizing Personalization

Introduction

Personalization refers to offering different pricing, promotions or content based on the shopper's attributes, known as traits. For example, an item's price may only be discounted for shoppers who are over sixty five years old. Personalized pricing is also referred to as Dynamic Pricing or Differential Pricing.

How Cortex Processes Traits

Cortex uses Subjects to manage its users. When a user logs in with an access token, a Subject is created and exists for the duration of the request. Personalization traits are modelled as attributes on the Subject and are called SubjectAttributes. If you have access to the Subject, then you also have access to the user's traits.

Subject Lifecycle

The Subject is created by the SubjectLifecycleFilter which assembles the Subject from HTTP inputs including the role, scope, and the user's identity details. This filter takes the traits sent through the x-ep-user-traits HTTP header and adds them to the subject's attributes. Subject attributes are automatically added to the Commerce Engine Selling Context and can influence pricing, promotions, and dynamic content delivery.

Cortex internally infers traits using SubjectAttributeLookups that contribute additional SubjectAttributes to the Subject. As with the x-ep-user-traits HTTP header, the SubjectAttributes are automatically added to the Commerce Engine Selling Context and can influence pricing, promotions and dynamic content delivery.

The image below describes an overview of the Subject's lifecycle.

How to add a new inferred trait

Add a new inferred trait by registering a new SubjectAttributeLookup with the SubjectAssembler. To register a new SubjectAttributeLookup, add a new OSGi bundle that includes an implementation of the SubjectAttributeLookupStrategy interface and exports it via OSGi Blueprint.

An example SubjectAttributeLookup:

@Singleton
@Named("myNewAttributeLookup")
public class MyNewAttributeLookup implements SubjectAttributeLookupStrategy {

  public Collection<SubjectAttribute> getSubjectAttributes(final String userId,
			final Collection<String> userRoles,
			final Collection<String> scopes,
			final HttpServletRequest request) {
				    // Create some SubjectAttributes!
            return ...;
  }
}
    

Exporting the SubjectAttributeLookup via blueprint:

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0
    http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
...
  <service ref="myNewAttributeLookup"
    interface="com.elasticpath.rest.relos.rs.subject.attribute.lookup.SubjectAttributeLookupStrategy" 
    ranking="10" />
...
</blueprint>
Note: id must match ref

The Named "myNewAttributeLookup" id must match the service ref in the Blueprint

How to configure a trait's precedence

With multiple SubjectAttributeLookup implementations registered with the Cortex OSGi container, attributes can potentially overlap. Therefore, lookups are evaluated in specific order to ensure the results returned for each request are consistent.

SubjectAttributeLookup implementations are configured with an OSGi Service Ranking to control the relative ordering they are evaluated in. Highest ranking lookups runs first and the first lookup wins. Out of the box, traits specified using the x-ep-user-traits HTTP header are evaluated first (rank 1000) and override any traits inferred using SubjectAttributeLookups. For example, if the gender trait is passed using x-ep-user-traits HTTP header, then the headerSubjectAttributeLookupStrategy runs first and takes precedence over the customerGenderTraitLookup (rank 100).

Service ranking attributes are optional. If rankings are not specified, then the SubjectAttributeLookup is assigned a default ranking of zero, which means it will run last. A SubjectAttributeLookup will not override traits supplied by previous lookups, so take care when ordering your lookups.

The following traits are provided out of the box:

Bundle Trait Lookup Service Ranking
ep-rs-authentication-header-epcommerce headerSubjectAttributeLookupStrategy 1000 (first by default)
ep-rs-personalization-epcommerce customerFirstTimeBuyerTraitLookup 400
ep-rs-personalization-epcommerce customerAgeTraitLookup 300
ep-rs-personalization-epcommerce customerRegisteredTraitLookup 200
ep-rs-personalization-epcommerce customerGenderTraitLookup 100 (last by default)
The ep-rs-authentication-header-epcommerce bundle:
        
<?xml version="1.0" encoding="UTF-8"?>
<blueprint
		xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">

	<!--  export services -->
	<service ref="headerSubjectAttributeLookupStrategy"
			 interface="com.elasticpath.rest.relos.rs.subject.attribute.lookup.SubjectAttributeLookupStrategy"
			 ranking="1000" />

</blueprint>
        
      
The ep-rs-personalization-epcommerce bundle:
        
      <?xml version="1.0" encoding="UTF-8"?>
      <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
        ...
        <service ref="customerFirstTimeBuyerTraitLookup"
          interface="com.elasticpath.rest.relos.rs.subject.attribute.lookup.SubjectAttributeLookupStrategy" 
          ranking="400" />

        <service ref="customerAgeTraitLookup"
          interface="com.elasticpath.rest.relos.rs.subject.attribute.lookup.SubjectAttributeLookupStrategy" 
          ranking="300" />

        <service ref="customerRegisteredTraitLookup"
          interface="com.elasticpath.rest.relos.rs.subject.attribute.lookup.SubjectAttributeLookupStrategy" 
          ranking="200" />

        <service ref="customerGenderTraitLookup"
          interface="com.elasticpath.rest.relos.rs.subject.attribute.lookup.SubjectAttributeLookupStrategy" 
          ranking="100" />
      </blueprint>
        
      

How to disable an existing trait

The SubjectAttributeLookups are registered using a dynamic OSGi Reference List. Removing or disabling any of the existing SubjectAttributeLookup bundles from the Cortex web application removes the associated trait.