Coveo Experience Hub setup for websites
Coveo Experience Hub setup for websites
This article explains how to set up the Coveo Experience Hub on your site for clients working in the ecommerce vertical.
Browser compatibility
Before you start setting up the Experience Hub on your website, make sure that you’re using the latest version of the Chrome browser as this is the only browser supported by our application. For more information, see Browser compatibility.
Setup steps
Perform the following steps:
Step 1: Add Experience Hub scripts
To log user events and allow the Experience Hub to work efficiently, you need to include the smartserve.js script on your site.
It’s also recommended that you include the UV API script to make the implementation of the Experience Hub easier.
smartserve.js
If you haven’t yet implemented Smartserve on your site, we recommend that you do so with an asynchronous setup. As a best practice, load the script as high up in the head of the page as possible:
<script src='//static.goqubit.com/smartserve-<YOUR_PROPERTY_ID>.js' async></script>
Note
The Content API requires contextual information to be passed to it, including details about the page, product, and the basket. If you need to hit the endpoint directly, you must send the contextual information in the request. |
Note
When using |
UV API
The Experience Hub uses data generated by the events emitted on your website.
To pass events to your website, you need to use The Universal Variable (UV) API script in your website.
The UV API is s a global event emitter used to pass underlying page or view information to third-party scripts.
Using the UV API script, all data is exposed as events using window.uv
.
All events must conform to schemas defined in the QProtocol schemas.
Note
The UV API script can only be used in IE8+, Firefox, Opera, Chrome, and Safari. |
Setting up and using the UV API
The UV API should be included as an inline script on the webpage at the top of the <head>
tag, immediately after the <meta charset… />
tag.
By embedding the API in the <head>
synchronously, any script in the page is able to emit or handle events without polling or waiting for asynchronous scripts to load.
The following piece of code shows how to import the script:
<script>
!function(){function n(){function n(n){p.level=n}function e(n,e){p.info(n,"event emitted"),e=c(e||{}),e.meta=e.meta||{},e.meta.type=n,u.push(e),r(),v.listeners=f(v.listeners,function(n){return!n.disposed})}function o(n,e,o){function r(){return p.info("Replaying events"),t(function(){s(v.events,function(t){c.disposed||l(n,t.meta.type)&&e.call(o,t)})}),f}function i(){return p.info("Disposing event handler"),c.disposed=!0,f}p.info("Attaching event handler for",n);var c={type:n,callback:e,disposed:!1,context:o||window};v.listeners.push(c);var f={replay:r,dispose:i};return f}function t(n){p.info("Calling event handlers"),a++;try{n()}catch(n){p.error("UV API Error",n.stack)}a--,r()}function r(){if(0===u.length&&p.info("No more events to process"),u.length>0&&a>0&&p.info("Event will be processed later"),u.length>0&&0===a){p.info("Processing event");var n=u.shift();v.events.push(n),t(function(){s(v.listeners,function(e){if(!e.disposed&&l(e.type,n.meta.type))try{e.callback.call(e.context,n)}catch(n){p.error("Error emitting UV event",n.stack)}})})}}function i(n,e,o){var t=v.on(n,function(){e.apply(o||window,arguments),t.dispose()});return t}function s(n,e){for(var o=n.length,t=0;t<o;t++)e(n[t],t)}function c(n){var e={};for(var o in n)n.hasOwnProperty(o)&&(e[o]=n[o]);return e}function l(n,e){return"string"==typeof n?n===e:n.test(e)}function f(n,e){for(var o=n.length,t=[],r=0;r<o;r++)e(n[r])&&t.push(n[r]);return t}var u=[],a=0,p={info:function(){p.level>n.INFO||console&&console.info&&console.info.apply(console,arguments)},error:function(){p.level>n.ERROR||console&&console.error&&console.error.apply(console,arguments)}};n.ALL=0,n.INFO=1,n.ERROR=2,n.OFF=3,n(n.ERROR);var v={on:o,emit:e,once:i,events:[],listeners:[],logLevel:n};return v}"object"==typeof module&&module.exports?module.exports=n:window&&void 0===window.uv&&(window.uv=n())}();
</script>
Step 2: Emit events
By embedding the API in the head synchronously, any script in the page is able to emit or handle events without polling or waiting for asynchronous scripts to load. See Coveo Experimentation Hub scripts for more information.
To emit events, call the uv.emit
method on the UV API script.
The events sent with this script are known as QProtocol events.
See ecommerce - QProtocol events for a complete list of the ecommerce events that are defined by this protocol.
The following example code shows how to send the ecView
and ecProduct
events:
<script>
uv.emit('ecView', {
type: 'product'
})
uv.emit('ecProduct', {
eventType: 'detail',
product: {
productId: '1209012233',
name: 'Stainless steel and leather watch'
}
})
</script>
Note
Before sending an event to the backend, smartserve.js retrieves context data stored in cookies and meta data such as the URL of the page. This data will be available to query. |
Any Coveo Experience Hub events emitted before the first |
The emitted event will have meta attached.
{
"meta": {
"type": "ecProduct"
},
"product": {
"id": "112-334-a",
"price": 6.99,
"name": "18th Birthday Baloon",
"category": ["Party Accessories", "Birthday Parties"]
},
"color": "red",
"stock": 6,
"eventType": "detail"
}
on
uv.on(type, handler, [context])
This method attaches an event handler to be called when a certain event type is emitted. The handler will be passed the event data and will be bound to the context object, if one is passed. If a regex is passed, the handler will execute on events that match the regex.
uv.on('ecProduct', function (data) {
console.log(data)
})
// => logs data when an `ecProduct` event is emitted
const subscription = uv.on(/.*/, function (data) {
console.log(data)
})
// => logs data for all events
The on method returns a subscription object which can detach the handler using the dispose method and can also be used to replay events currently in the event array.
Note that subscriptions that have been disposed won’t call the handler when replay is called. Let’s look at an example:
subscription.dispose()
// => detatches the event handler
subscription.replay()
// => calls the handler for all events currently in uv.events
once
uv.once(type, handler, [context])
This method attaches an event handler that will be called once, on the next event emitted that matches the type specified. The handler will be passed the event data and will be bound to the context object, if one is passed.
It returns a subscription object which can detach the handler using the dispose method. If a regex is passed, the handler will execute on the next event to match the regex. Let’s look at an example:
uv.once('ecProduct', function (data) {
console.log(data)
})
emit('ecProduct')
// => logs data
emit('ecProduct')
// => does not log
Events
The events array is a cache of events emitted since the last page load. By iterating over the array it’s possible to interpret the user journey or the current state of the page.
NPM module
The uv-api is available on the NPM registry.
npm i uv-api --save
The module exports a createUv
function if required using CommonJS.
const createUv = require('uv-api')
const uv = createUv()
uv.emit('ecView')
The fields given in the table below are required fields. Additional bonus fields can be sent as specified in the reference documentation. |
Click expand/collapse to see the corresponding tables.
Basic audiences
expand/collapse
Required mostly for audience targeting.
Event | Field (JS Data Type) | Description | Conditions |
---|---|---|---|
ecUser |
user.id (String) |
A unique user ID. Can be a hash of the username and/or email address |
Logged in: checks for the presence or absence of a user ID Custom list (User ID): matches the user’s ID to an uploaded list |
user.email (String) |
The user’s primary email address |
Custom list (Email list): matches the user’s email to an uploaded list |
|
user.loyalty.membershipType |
The user’s loyalty membership type, if available |
Membership type: matches the user’s value |
|
ecProduct (PDP) |
product.productId (String) |
Unique identifier to distinguish between visually different options of a product, such as colors |
Product ID: matches the current product’s ID |
product.name (String) |
The product’s name, which should match the name shown on the product page |
Product Name: matches the current product’s name |
|
product.categories (Array of Strings) |
A list of one or more product categories the product belongs to. Each category is a full category path, with each level separated by > |
Product category: matches one of the the current product’s categories |
|
ecView |
type (String) |
The type of view. Can be one of |
Page type: matches the current page’s type |
subtypes (Array of Strings) |
An unordered list of subtypes to describe the view |
Page subtype: matches one of the current page’s subtypes |
|
language (String) |
The language used in this view. Must be an IETF language tag (for example, |
Language: matches the current page’s language |
|
currency (String) |
The ISO 4217 currency code for the visitor (for example, |
Currency: matches the current page’s currency |
Audiences based on visitor history
expand/collapse
Required to build an audience based on a person’s browsing or purchase history.
Event | Field (JS Data Type) | Description |
---|---|---|
ecProduct (PDP) |
product.productId (String) |
Unique identifier to distinguish between visually different options of a product, such as colors |
product.categories (Array of Strings) |
A list of one or more product categories the product belongs to. Each category is a full category path, with each level separated by > |
|
product.manufacturer (String) |
The product manufacturer, recommended when a product inventory includes multiple brands |
|
eventType (String) |
The type of product event (for example, |
|
ecBasketItemTransaction (Confirmation page) |
product.productId (String) |
Unique identifier to distinguish between visually different options of a product, such as colors |
transaction.id (String) |
A unique transaction ID |
Reporting
expand/collapse
Required to report metrics for campaigns and experiences.
Event | Field (JS Data Type) | Description |
---|---|---|
ecBasketTransactionSummary |
transaction.id (String) |
A unique transaction ID |
basket.total.value (Number) |
The basket total after the application of discounts, promotions, shipping costs, etc |
|
basket.total.currency (String) |
The ISO 4217 currency code (for example, |
Personalized content
expand/collapse
In the following table, you can see a breakdown of the QProtocol events and fields required for personalized content campaigns.
Event | Field (JS Data Type) | Description |
---|---|---|
ecView |
type (String) |
The type of view. Can be one of |
subtypes (Array of Strings) |
An unordered list of subtypes to describe the view |
|
language (String) |
The language used in this view. Must be an IETF language tag (for example, |
|
currency (String) |
The ISO 4217 currency code for the visitor (for example, |
|
ecProduct (PDP) |
product.productId (String) |
Unique identifier to distinguish between visually different options of a product, such as colors |
product.categories (Array of Strings) |
A list of one or more product categories the product belongs to. Each category is a full category path, with each level separated by > |
|
product.name (String) |
The product’s name, which should match the name shown on the product page |
You can also use the following data points:
Data Point | Data Source |
---|---|
Device |
|
Browser |
|
Location (city, area, region, country) |
|
Current page URL |
data enrichment process |
Product recommendations
expand/collapse
Coveo Qubit recommendations strategies
In the following table, you can see a breakdown of the QProtocol events and fields required to deliver Product Recommendations (PR) campaigns using one of Qubit’s strategies
Event | Field (JS Data Type) | Description |
---|---|---|
ecView |
type (String) |
The type of view. Can be one of |
language (String) |
The language used in this view. Must be an IETF language tag (for example, |
|
currency (String) |
The ISO 4217 currency code for the visitor (for example, |
|
ecProduct |
product.productId (String) |
Unique identifier to distinguish between visually different options of a product, such as colors |
product.price.currency (String) |
The ISO 4217 currency code (for example, |
|
eventType (String) |
Must be |
|
ecBasketItemTransaction |
transaction.id (String) |
A unique transaction ID |
product.productId (String) |
Unique identifier to distinguish between visually different options of a product, such as colors |
|
product.sku (String) |
Unique identifier to distinguish the different variations a product can be purchased in, such as size |
Google recommendations strategies
In addition to the campaign events described above, which include implementing Basic audiences, Audiences based on visitor history, and reporting, it’s necessary to emit the events shown in the following table in order to utilize the Google recommendations strategies.
Event | Field (JS Data Type) | Description |
---|---|---|
ecBasketItemTransaction |
product.productId (String) |
Unique identifier to distinguish between visually different options of a product, such as colors |
product.price.value (Number) |
The price of the product after any discounts, promotions, etc, rounded to 2 decimal places |
|
product.price.currency (String) |
The ISO 4217 currency code (for example, |
|
product.sku (String) |
Unique identifier to distinguish the different variations a product can be purchased in, such as size |
|
quantity (Number) |
The number of products described by the line item |
|
subtotal.value (Number) |
The subtotal of the products described by the line item taking into account the current price and quantity before the application of taxes, discounts, promotions, shipping costs, etc |
|
subtotal.currency (String) |
The ISO 4217 currency code (for example, |
|
transaction.id (String) |
A unique transaction ID |
|
ecBasketItem |
product.productId (String) |
Unique identifier to distinguish between visually different options of a product, such as colors |
product.sku (String) |
Unique identifier to distinguish the different variations a product can be purchased in, such as size |
|
ecBasketItemAction |
product.productId (String) |
Unique identifier to distinguish between visually different options of a product, such as colors |
action (String) |
|
|
product.sku (String) |
Unique identifier to distinguish the different variations a product can be purchased in, such as size |
|
ecProduct |
product.productId (String) |
Unique identifier to distinguish between visually different options of a product, such as colors |
product.sku (String) |
Unique identifier to distinguish the different variations a product can be purchased in, such as size |
|
product.price.value (Number) |
The price of the product after discounts, promotions, etc, rounded to 2 decimal places. You do not need to include this field if it’s present in the product catalog |
|
ecView |
type (String) |
The type of view. Can be one of |
language (String) |
The language used in this view. Must be an IETF language tag (for example, |
|
currency (String) |
The ISO 4217 currency (for example, |
Product badging
expand/collapse
In the following table, you can see a breakdown of the QProtocol events and fields required for product badging campaigns.
Event | Field (JS Data Type) | Description |
---|---|---|
ecView |
type (String) |
The type of view. Can be one of |
language (String) |
The language used in this view. Must be an IETF language tag (for example, |
|
currency (String) |
The ISO 4217 currency code for the visitor (for example, |
|
ecProduct |
product.productId (String) |
Unique identifier to distinguish between visually different options of a product, such as colors |
eventType (String) |
The type of product event. On a product detail page (PDP) you must use |
|
ecBasketItemTransaction |
product.productId (String) |
Unique identifier to distinguish between visually different options of a product, such as colors |
ecBasketItemAction |
product.productId (String) |
Unique identifier to distinguish between visually different options of a product, such as colors |
action (String) |
|
|
product.sku (String) |
Unique identifier to distinguish the different variations a product can be purchased in, such as size |
Product Insights
expand/collapse
The following events are required to power Product insights.
Event | Field (JS Data Type) | Description |
---|---|---|
ecView |
type (string) |
The type of view. Must be |
language (String) |
The language used in this view. Must be an IETF language tag (for example, |
|
currency (String) |
The ISO 4217 currency code for the visitor (for example, |
|
ecProduct |
product.productId (String) |
Unique identifier to distinguish between visually different options of a product, such as colors |
product.price.value (Number) |
The price of the product after any discounts, promotions, etc, rounded to 2 decimal places. Must match price on PDP and must not be 0 or |
|
product.eventType (String) |
The type of product event. Must be |
|
ecBasketItemTransaction |
product.productId (String) |
Unique identifier to distinguish between visually different options of a product, such as colors |
product.price.value (Number) |
The price of the product after any discounts, promotions, etc, rounded to 2 decimal places. Must match price on PDP and must not be 0 or |
|
quantity (Number) |
The number of products described by the line item |
Note
Although this isn’t a requirement, we recommended that you emit the |
Step 3: Generate product feed
To supplement the data provided by QProtocol, you’re required to provide additional product data in the form of a product feed. You can import your Google product feed into the Experience Hub to drive product recommendations.
To work with a different product feed, reach out to your CSM.
Refer to the following table for details of the required data points you need to provide.
It’s important that the product ID emitted in QProtocol events matches the ID in your product feed. |
Data Point | Google Feed Attribute | Description | Example |
---|---|---|---|
Product ID |
Your product’s unique identifier |
A2B4 |
|
Product name |
Your product’s name |
Mens Pique Polo Shirt |
|
Product category |
Product category for your product |
Shirts |
|
Product URL |
Your product’s landing page |
||
Image URL |
The URL of your product’s main image |
||
Stock or Availability |
Your product’s availability |
In stock |
|
Price |
Your product’s price in the format |
15.00 USD |
|
Language |
Inferred from locale |
|
|
Brand of Manufacturer |
Your product’s brand name |
BrandA |
|
Gender |
The gender for which your product is intended |
|
Step 4: Tutorials
Refer to Tutorials.