Integrate a recommendation interface in a web page
Integrate a recommendation interface in a web page
This is for:
DeveloperWhen you want to take advantage of a Coveo Machine Learning (Coveo ML) Content Recommendation (CR) model on a site, you should integrate a Coveo JavaScript Search Framework recommendation interface into each page in which you want to display recommendations (see Deploy Content Recommendations (CR)).
To do this, you need to:
-
Configure a search endpoint for the recommendation interface (see the
SearchEndpoint.configureCloudV2Endpoint
method). -
Initialize the recommendation interface (see the
initRecommendation
top-level function). -
Configure the recommendation interface in the page markup (see the
Recommendation
component).
The following sample markup shows how to integrate a recommendation interface.
<head>
<!-- ... -->
<!-- Import the required Coveo JavaScript Search Framework resources. -->
<link rel="stylesheet"
href="https://static.cloud.coveo.com/searchui/v2.10107/css/CoveoFullSearch.css"/>
<script class="coveo-script"
src="https://static.cloud.coveo.com/searchui/v2.10107/js/CoveoJsSearch.Lazy.min.js">
</script>
<script>
document.addEventListener("DOMContentLoaded", () => {
// Configure a search endpoint for the recommendation interface.
Coveo.SearchEndpoint.configureCloudV2Endpoint("<ORGANIZATION_ID>", "<ACCESS_TOKEN>");
// Initialize the recommendation interface.
Coveo.initRecommendation(Coveo.$$(document).find("<RECOMMENDATION_INTERFACE_SELECTOR>"));})
</script>
<!-- ... -->
</head>
<body>
<!-- ... -->
<!-- Configure the recommendation interface in the page markup -->
<div id="recommendation"
class="CoveoRecommendation"
data-results-per-page="5"
data-pipeline="<RECOMMENDATION_QUERY_PIPELINE>">
<div class="CoveoAnalytics" data-search-hub="<RECOMMENDATION_SEARCH_HUB>"></div>
<div class="coveo-recommendation-header">
<div class="coveo-recommendation-title">RECOMMENDATION_INTERFACE_TITLE</div>
</div>
<div class="coveo-recommendation-body">
<div class="CoveoResultList"></div>
</div>
</div>
<!-- ... -->
</body>
Where:
-
<ORGANIZATION_ID>
The unique identifier of the target Coveo organization (for example,
mycoveocloudvorganizationg8tp8wu3
). -
<ACCESS_TOKEN>
A public API key that only grants the privileges to execute queries and push analytics data in the target organization, or a valid search token if the page requires user authentication (see Search token authentication).
-
<RECOMMENDATION_INTERFACE_SELECTOR>
A CSS selector that matches the HTML element with the
CoveoRecommendation
class in the search page markup. For example, if the target element has theid="recommendation"
attribute,#recommendation
would be a good selector. -
<RECOMMENDATION_QUERY_PIPELINE>
The name of the query pipeline to enforce for each query originating from the recommendation interface (for example,
techDocsRecommendations
). This should be set to the name of the query pipeline which contains the CR model that you want to use.NoteFor the sake of simplicity, the above code sample suggests that you enforce the query pipeline routing directly in the markup configuration of your recommendation interface.
A more flexible approach would be to omit the
data-pipeline
attribute in theRecommendation
component markup configuration, and instead use the condition-based query pipeline routing mechanism. -
<RECOMMENDATION_SEARCH_HUB>
Leading practiceSetting the recommendation interface
searchHub
to a distinctive and meaningful value is useful for reporting.The name of the origin level 1 to use when sending events from the recommendation interface. This value also defines the search hub to use for all queries originating from the recommendation interface.
NoteCR models don’t take the
searchHub
query parameter into account. However, each model can be configured to only learn from search and click events that match certain filters (for example, if the events haveCommunitySearch
as theiroriginLevel1
).UA view events don’t have an
originLevel1
, but they can still be filtered according to theircontentType
. -
RECOMMENDATION_INTERFACE_TITLE
The title to display for the recommendation interface (for example, People Also Viewed).
Notes
|
Complete JavaScript Search Framework code sample
You’ve configured a CR model in the techDocRecommendations
query pipeline of the mycoveocloudvorganizationg8tp8wu3
organization.
You include code similar to the following in the pages of your technical documentation website to track users' action history, send view events, and render a People Also Viewed recommendation interface.
<!DOCTYPE html>
<!-- Set `language` metadata for view events send from this page. -->
<html lang="en">
<head>
<!-- Set `title` metadata for view events. sent from this page. -->
<title>Customize the Acme Widget</title>
<!-- ... -->
<!-- Import required Coveo JavaScript Search Framework resources. -->
<link rel="stylesheet"
href="https://static.cloud.coveo.com/searchui/v2.10107/css/CoveoFullSearch.css"/>
<script class="coveo-script"
src="https://static.cloud.coveo.com/searchui/v2.10107/js/CoveoJsSearch.Lazy.min.js">
</script>
<!-- Import script to send view events and record actions history. -->
<script type="text/javascript"
src="https://static.cloud.coveo.com/coveo.analytics.js/2/coveoua.js">
</script>
<script>
// Declare variables.
namespace = new function() {
// The API key or search token to use to authenticate the HTTP requests.
this.accessToken = function() {
/* Could return a public API key granting only the Execute Queries and
Usage Analytics - Edit privileges in the target Coveo organization
organization, or call a server-side service to return a valid search
token. */
}();
// The name of a field that can map the current page to an index item.
this.contentIdKey = "@clickableuri";
// The `contentIdKey` field value for the current page.
this.contentIdValue = window.location.href;
// Optional. The type of content being tracked.
this.contentType = "documentation";
// Optional. Custom user context information.
this.userRole = function() {
// Could return a value such as "employee" or "partner".
}();
this.userTechnicalSkillLevel = function() {
// Could return a value such as "intermediate" or "advanced".
}();
// ... Additional custom user context ...
// The unique identifier of the target Coveo organization.
this.organizationId = "mycoveocloudvorganizationg8tp8wu3";
};
// Record actions history and send view events.
coveoua("init", namespace.accessToken);
coveoua("send", "pageview", {
contentIdKey: namespace.contentIdKey,
contentIdValue: namespace.contentIdValue,
contentType: namespace.contentType,
context_userRole: namespace.userRole,
context_userTechnicalSkillLevel: namespace.userTechnicalSkillLevel
// ... Additional custom user context ...
});
// Configure search endpoint.
document.addEventListener("DOMContentLoaded", () => {
Coveo.SearchEndpoint.configureCloudV2Endpoint(namespace.organizationId,
namespace.accessToken);
let peopleAlsoViewed = Coveo.$$(document).find("#recommendation");
// Add user context to recommendation interface queries and UA events.
Coveo.$$(peopleAlsoViewed).on("buildingQuery", function(e, args) {
args.queryBuilder.addContext({
"userRole": namespace.userRole,
"userTechnicalSkillLevel": namespace.userTechnicalSkillLevel
});
});
// Initialize recommendation interface
Coveo.initRecommendation(peopleAlsoViewed);
});
</script>
<!-- ... -->
</head>
<body>
<!-- ... -->
<!-- Configure recommendation interface in page markup. -->
<div id="recommendation"
class="CoveoRecommendation"
data-results-per-page="5"
data-pipeline="techDocRecommendations">
<div class="CoveoAnalytics"
data-search-hub="techDocSitePeopleAlsoViewed"></div>
<div class="coveo-recommendation-header">
<div class="coveo-recommendation-title">People Also Viewed</div>
</div>
<div class="coveo-recommendation-body">
<div class="CoveoResultList"></div>
</div>
</div>
<!-- ... -->
</body>
</html>
Request backup recommendations
In a secured search context, the current user may not be permitted to see all of the items which are requested by a CR model.
You create a recommendation interface whose output may include items from a source that indexes permissions.
In the markup configuration of your Recommendation
component, you set the data-results-per-page
attribute to 5
.
Whenever your recommendation interface sends a query, the CR model in the target query pipeline generates a disjunction query expression (dq
) which requests the five items that it deems the most contextually relevant.
However, because the CR model isn’t aware of security identities or effective permissions, it may request five items which the current user isn’t permitted to see.
In this case, the index won’t return any results. Consequently, the recommendation interface either displays an empty result list, or remains entirely invisible.
To reduce the chances of a recommendation interface yielding less than the desired number of results, you may want to request more items from the CR model than the specified data-results-per-page
value.
This can be done by using customQueryParameters
when associating your CR model with a query pipeline.
This lets you specify additional parameters to send to Coveo ML on all queries.
For example, you could request ten recommendations from the model, but only request five results from the index by using the num
mlParameters
.
{
"position": 1,
"modelId": "XXXXXX_eventrecommendation_XXXXXXXX_XXXX_XXXX_XXXX_XXXXXXXXXXXX",
"condition": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"modelEngine": "eventrecommendation",
"rankingModifier": 1000,
"cacheMaximumAge": "PT10S",
"exclusive": true,
"customQueryParameters": {
"num": <NUMBER_OF_RECOMMENDATIONS_TO_REQUEST>
},
"useAdvancedConfiguration": false
}
Where you replace <NUMBER_OF_RECOMMENDATIONS_TO_REQUEST>
with the number of recommendations that you want to request.
Enable content recommendations padding
When configuring a search endpoint for a recommendation interface, you may want your CR model to pad its output with popular or trending items, up to the desired number of results.
Doing so can be useful if you want your recommendation interface to display the desired number of results even when the target ML model has not yet learned from enough UA data, or when the user’s action history is empty.
This can be done by using customQueryParameters
when associating your CR model with a query pipeline.
This lets you specify additional parameters to send to Coveo ML on all queries, such as the padding
mlParameters
.
{
"position": 1,
"modelId": "XXXXXX_eventrecommendation_XXXXXXXX_XXXX_XXXX_XXXX_XXXXXXXXXXXX",
"condition": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"modelEngine": "eventrecommendation",
"rankingModifier": 1000,
"cacheMaximumAge": "PT10S",
"exclusive": true,
"customQueryParameters": {
"padding": "<PADDING_TYPE>"
},
"useAdvancedConfiguration": false
}
Where you replace <PADDING_TYPE>
with the padding
value that you want to use (this can be either popular
or trending
).
Leverage user context data in a recommendation interface
If you send user context custom data in your view events, you should ensure that every query sent from your recommendation interface includes the current user context. Otherwise, recorded user context data will have no impact on the output of your CR model.
const recommendationElement = Coveo.$$(document).find("<RECOMMENDATION_INTERFACE_SELECTOR>");
// Add user context to recommendation interface queries and UA events.
Coveo.$$(recommendationElement).on("buildingQuery", function(e, args) {
args.queryBuilder.addContext({
"<USER_CONTEXT_KEY_1>": "<USER_CONTEXT_VALUE_1>",
"<USER_CONTEXT_KEY_2>": "<USER_CONTEXT_VALUE_2>",
// ...
"<USER_CONTEXT_KEY_N>": "<USER_CONTEXT_VALUE_N>"
});
});
Coveo.initRecommendation(recommendationElement);
Initializing an embedded recommendation interface
When you include a Recommendation
component inside a SearchInterface
component (that is, in a full search page), the initRecommendation
function call requires a second argument which references the main search interface element.
const recommendationElement = Coveo.$$(document).find("<RECOMMENDATION_SELECTOR>");
const searchInterfaceElement = Coveo.$$(document).find("<SEARCH_INTERFACE_SELECTOR>");
Coveo.initRecommendation(recommendationElement, searchInterfaceElement);