Key concepts

November 11, 2022
Note: Marketing Factory is renamed to jExperience in version 1.11 and Apache Unomi is renamed to jCustomer. The 1.10 documentation has been updated to reflect the product name change.

jCustomer gathers information about users actions, information that is processed and stored by jCustomer services. The collected information can then be used to personalize content, derive insights on user behavior, categorize the profiles into segments along user-definable dimensions or acted upon by algorithms.

Items and scope

jCustomer structures the information it collects using the concept of Item which provides the base the context server needs to process and store the data. Items are persisted according to their type (structure) and identifier (identity). This base structure can be extended, if needed, using properties in the form of key-value pairs.

Additionally, tracked items are also gathered by scope which allows the context server to group together related items. Scopes usually pertain to a given site being analyzed, though they can span across sites depending on the desired analysis granularity. Scopes allow clients accessing the context server to filter data to only see relevant data.

{
    itemType: <type of the item>,
    scope: <scope>,
    itemId: <item identifier>,
    properties: <optional properties>
}

jCustomer defines a built-in scope (called systemscope) that clients can use to share data across scopes.

Events

Users' actions are conveyed from clients to the context server using events. Of course, the required information depends on what is collected and users' interactions with the observed systems but events minimally provide a type, a scope and source and target items. You can imagine an event as being a sentence, the event's type being the verb, the source the subject and the target the object:

{
    eventType: <type of the event>,
    scope: <scope of the event>,
    source: <Item>,
    target: <Item>,
    properties: <optional properties>
}

Profiles

By processing events, jCustomer progressively builds a picture of who the user is and how they behave. This knowledge is embedded in Profile objects. A profile is an Item with any number of properties and optional segments and scores. jCustomer provides default properties to cover common data (name, last name, age, email, etc.) as well as default segments to categorize users. jCustomer users are, however, free and even encouraged to create additional properties and segments to better suit their needs.

Items and types

Any information that is processed by and stored in jCustomer is structured as an Item. However, items only define a basic, generic structure. Types provide additional structure and semantics to generic items. By defining a new type, users specify which properties (including the type of value they accept) are available to items of that specific type.

Some types can be dynamically defined at runtime by calling the REST API while other extensions are done via jCustomer plugins. Part of extending jCustomer, therefore, is a matter of defining new types and specifying which kind of jCustomer entity (e.g. profiles) they can be affected to. For example, the following JSON document can be passed to jCustomer to declare a new property type identified (and named) tweetNb, tagged with the social tag, targeting profiles and using the integer value type.

{
    itemId: 'tweetNb', 
    itemType: 'propertyType',
    metadata: {
        id: 'tweetNb',
        name: 'tweetNb'
    },
    tags: ['social'],
    target: 'profiles',
    type: 'integer'
}

jCustomer defines default value types: date, email, integer and string, all pretty self-explanatory. While you can think of these value types as "primitive" types, it is possible to extend jCustomer by providing additional value types.

Providing context to jCustomer

In order to be able to build a profile based on user actions, jCustomer requires data. This data is provided by clients which can choose how to do so. A convenient way to store and provide that contextual information is to leverage the Customer Experience Digital Data Layer digitalData object that is injected into the browser’s window object.

Using jExperience

jExperience makes it easier to provide the required information to the context server by automatically populating and injecting the digitalData object for the benefit of any javascript application running on a site for which jExperience has been activated.

jExperience populates the digitalData object with metadata that can be sent to the context server, notably the scope configured for the site (which is usually the site's key), metadata about the site and the current page. jExperience also adds to this data the base URL for the context server:

window.digitalData = {
  "scope": <current scope>,
  "site": {
    "siteInfo": {
      "siteID": <site identifier>
    }
  },
  "page": {
    "pageInfo": {
      "pageID": <page identifier>,
      "pageName": <page name>,
      "pagePath": <relative path of the page from the site root>,
      "destinationURL": <the current URL>,
      "referringURL": <the URL from which we came from if any>,
      "language": <the current language>
    },
    "category": {},
    "attributes": {}
  },
  "contextServerPublicUrl": <base URL where the context server is configured>
}

After jExperience loads the initial page the user is viewing, it contacts the context server to retrieve default context information automatically. This results in a cxs object being injected in the global javascript variable space, thus making it available to any javascript code running on the page:

cxs = {
    profileId: <identifier of the current user's profile>,
    sessionId: <identifier of the current user's session>,
    profileProperties: <optional, mapping profile property names to their values>,
    sessionProperties: <optional, mapping session property names to their values>,
    profileSegments: <optional array of segments the user matches>,
    filteringResults: <optional array of filtering results>,
    trackedConditions: <optional array of tracked conditions>
}

Since the cxs object contains the identifiers for the profile and session associated with our user, we could use this information to retrieve more details from the context server.

Using jCustomer without jExperience

If you are not using jExperience, it is still possible (of course!) to provide context to jCustomer. You, however, require a little bit more work. In order to replicate the digitalFactory object as provided by jExperience in your Jahia components, you could use the following code in your JSPs:

<%--@elvariable id="renderContext" type="org.jahia.services.render.RenderContext"--%>
<%--@elvariable id="resource" type="org.jahia.services.render.Resource"--%>

<c:set var="scriptURL" value='${renderContext.request.secure ? "https://localhost:9443" : "http://localhost:8181"}'/>
<c:set var="pageName" value='${fn:escapeXml(resource.node.displayableName)}'/>

<template:addResources type="inlinejavascript">
    <script type="application/javascript">
        window.digitalData = window.digitalData || {
                "scope": "${renderContext.site.siteKey}",
                "site": {
                    "siteInfo": {
                        "siteID": "${resource.node.resolveSite.identifier}"
                    }
                },
                "page": {
                    "pageInfo": {
                        "pageID": "${resource.node.identifier}",
                        "pageName": "${pageName}",
                        "pagePath": "${resource.node.path}",
                        "destinationURL": document.location.href,
                        "referringURL": document.referrer,
                        "language": "${resource.locale}"
                    }
                },
                "contextServerPublicUrl": "${scriptURL}"
            };
    </script>
</template:addResources>

Note, however, that we hardcode the jCustomer server’s URL in the javascript.

Using jCustomer without jExperience and Jahia

Of course, you can still interact with jCustomer without either jExperience or Jahia, you would just need to provide the appropriate contextual information based on your application needs and constraints.