Experience API reference
Experience API reference
This is for:
DeveloperAll variation.js
and triggers.js
files receive an object full of useful stuff.
In this article we’ll show you what’s contained within that object and why you might want to use it.
meta
module.exports = function variation (options) {
console.log(options.meta)
}
The options.meta
object contains a bunch of useful information about the currently executing experience and variation:
Attribute | Description |
---|---|
cookieDomain |
The domain value that cookies have been configured to be stored against. This is useful if you need to store cookies in a consistent way. |
trackingId |
The tracking ID of the property on which the experience is executing. |
isPreview |
Whether the variant is executing in preview mode (can be useful if you want to avoid sending data while previewing, for example). |
vertical |
A code representing your industry sector. This affects what events you should send and their prefix. |
namespace |
The value of your configured namespace if you have one. This allows you to define a custom schema. |
experienceId |
The ID of the currently executing experience. |
iterationId |
The ID of the currently executing iteration. |
variationId |
The ID of the currently executing variation. |
variationMasterId |
The master ID of the currently executing variation. |
variationIsControl |
Whether the currently executing variation is a control variation. |
visitorId |
The visitor ID. |
data
module.exports = function variation (options) {
console.log(options.data)
}
The options.data
object contains input captured through the configurable content feature.
state
module.exports = function variation (options) {
console.log(options.state)
}
The options.state
methods offer a simple way to pass data between the triggers.js
file and the variation.js
file:
module.exports = function triggers (options) {
options.state.set('message', 1)
return true
}
function execution (options) {
console.log(options.state.get('message')) // 1
}
log
module.exports = function variation (options) {
console.log(options.log)
}
A stylish logger, useful for development of experiences. See https://github.com/QubitProducts/driftwood for more info:
module.exports = function variation (options) {
try {
options.log.info('hello from variation ' + options.variationMasterId)
throw new Error('stone')
} catch (eek) {
options.log.error('', eek)
}
}
getVisitorState
module.exports = function variation (options) {
options.getVisitorState().then(function (state) {
console.log(state)
})
}
This method allows you to get useful information about a user, including an IP address.
The getVisitorState
method returns a sync-p
style promise usually resolved synchronously, but on the first view of a session, syncing with the lookup API will cause it to be asynchronous.
Cross-domain setups will always have an asynchronous getVisitorState
method.
However, this setup is rare.
Attribute | Description |
---|---|
viewTs |
A timestamp for the most recent view event |
pageViewNumber |
The number of views the visitor has had |
cookiePersists |
False if the user’s cookie fails to persist |
timezoneOffset |
The timezone offset of the visitor in minutes from UTC |
visitorId |
Equivalent of context Id and cookie Id that’s randomly assigned to each visitor to identify them on your site - device specific |
conversionNumber |
The number of conversions the visitor has made - updated on the next view event after a conversion |
conversionCycleNumber |
The number of conversion cycles the visitor has had across their lifetime.The conversionCycleNumber increments only on the session following a session with one or more conversions |
lifetimeValue |
The total amount transacted by the visitor over their lifetime - updated at the beginning of the next session |
firstViewTs |
The date of the first View for the visitor |
lastViewTs |
The date of the last View for the visitor |
viewNumber |
The number of view event across the user’s lifetime |
entranceViewNumber |
The number of views the visitor has seen in the entrance |
sessionNumber |
The number of sessions the visitor has had across their lifetime |
entranceNumber |
The number of entrances the visitor has had across their lifetime |
ipAddress |
The IP Address of the device |
entranceTs |
Timestamp for when the entrance was initiated |
sessionViewNumber |
The number of views the visitor has seen in the session |
eventNumber |
The sequence number of the event for the current page view |
sessionTs |
Timestamp for when the session was initiated |
sample |
A number between 0 and 99 999 based on a hash of the visitor Id |
city |
The city name |
cityCode |
The city code |
country |
The country name |
countryCode |
The ISO 4217 currency code for the user (for example, |
latitude |
The latitude value |
longitude |
The longitude value |
area |
The area name |
areaCode |
The area code |
region |
The region name |
regionCode |
The region code |
Leading-practice
A typical use case for getting a user’s IP address is to exclude a range of IP addresses from Qubit tests. |
getBrowserState
module.exports = function variation (options) {
options.getBrowserState().then(function (state) {
console.log(state)
})
}
Returns useful information about the user’s browser.
The getBrowserState
method returns a sync-p
style promise that always resolves synchronously.
Attribute | Description |
---|---|
url |
The current URL |
host |
The current host |
referrerUrl |
The referrer URL |
doNotTrack |
Whether the user has expressed a preference not to be tracked by web sites |
ua.deviceType |
The users' device type |
ua.deviceName |
The users' device name |
ua.osName |
The users' OS name |
ua.osVersion |
The users' OS version |
ua.browserName |
The users' Browser name |
ua.browserVersion |
The users' Browser version |
ua.userAgent |
The users' User Agent string |
isBot |
Whether the user is a bot |
time |
A timestamp for when the users' browser state was computed |
screenWidth |
The users screen width |
screenHeight |
The users screen height |
poll
Poll allows you to wait for:
-
The presence of DOM elements
-
The presence of window variables
-
Arbitrary conditions
and returns a promise for those elements, variables or the results of your custom poll functions:
// Wait for the presence of DOM elements by passing in a selector:
options.poll('body > .nav').then(function (nav) {
console.log(nav)
})
// Wait for window variables to be defined:
options.poll('window.foo.bar').then(function (bar) {
console.log(bar)
})
// Wait for arbitrary conditions to become truthy by passing in a custom function:
options.poll(() => true).then(result => console.log(result))
// Mix and match:
options.poll(['body > .nav', 'window.foo', () => 1234]).then(function ([nav, foo, id]) {
console.log(nav, foo, id)
})
// Create a poller instance with several targets
var poller = options.poll([
'body > .nav',
'window.foo.bar',
() => true
])
// Start polling
poller
// returns a promise for the items being polled for
.then(function ([nav, bar, truthy]) {
console.log(nav, bar, truthy)
})
// Stop polling
poller.stop()
// Start polling again
poller.start()
This uses @qubit/poller under the hood, but is configured to provide useful logging when in preview mode.
emitCustomGoal
const Promise = require('sync-p')
module.exports = function triggers (options) {
const $ = require('jquery')
let $button
return options.poll([ '#add-to-bag' ]).then(handleButtonClick)
function handleButtonClick ([target]) {
return new Promise(resolve => {
$button = $(target)
$button.on('click', trackAddToBagClick)
options.onRemove(() => $button.off('click', trackAddToBagClick))
function trackAddToBagClick () {
options.emitCustomGoal('add-to-bag:click', {
description: 'The user clicked the "add to bag" button' // (256 characters max)
})
resolve()
}
})
}
}
You can track custom goals events within your experience by emitting a custom goal event.
To make these events appear in your experience results dashboard, you need to create a custom goal that corresponds to the event you are tracking:
Note
We increment the count for a custom goal each time |
emitCustomMetric
module.exports = function variation (options) {
const createWidget = require('super-widget')
const settings = { type: 4 }
const widget = createWidget(settings)
widget.on('click', () => options.emitMetric('widget.clicked'))
widget.open()
}
Metric events are similar to custom goal events except they aren’t tracked relative to the control variation.
In other words, it’s ideal for tracking things that only happen as a result of the experience execution, for example, recommendation.clicked
or widget.opened
.
You can emit a metric event simply by calling options.emitMetric(type)
.
Leading-practice
Use the convention noun.verb for specifying |
emitMetric
also optionally accepts productId and extra arbitrary info:
module.exports = function variation (options) {
const createWidget = require('super-widget')
const settings = { type: 4 }
const widget = createWidget(settings)
widget.on('click', productId => options.emitMetric('widget.clicked', productId, settings))
widget.open()
}
redirectTo
module.exports = function variation (options) {
options.redirectTo('/success')
}
Sometimes an experience might want to redirect a visitor to another page.
Doing so within an experience can result in the page unloading very quickly, and this can sometimes prevent your experience from registering that it was seen, which can affect your experience stats.
Rather than delaying your experience, this utility ensures that all the appropriate events have been sent before triggering a redirect, and is the recommended way to trigger a redirect from an experience.
registerContentAreas
To register a content area on the page, experiences can use the registerContentAreas
API:
module.exports = function variation (options) {
// This tells explorer which parts of the page this experience will be interacting with
// When this experience is active, the experience highlighter will highlight these areas
options.registerContentAreas(['.header', '.footer'])
}
You can also dynamically register and unregister content areas while the experience is executing:
module.exports = function variation (options) {
options.registerContentAreas(['.header', '.footer'])
setTimeout(() => {
options.unregisterContentAreas(['.footer'])
}, 500)
}
When you register content areas augmented by your experiences, you will then be able to use the Explorer tool to browse your site and those content areas will be highlighted when your experience executes.
unregisterContentAreas
The unregisterContentAreas API simply unregisters content areas registered via the registerContentAreas API.
uv
Part of the client-side API is our UV API. This enables experience developers to build experiences that take advantage of our event-based protocol.
On
uv.on(type, handler, [context])
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
var subscription = uv.on(/.*/, function (data) {
console.log(data)
})
// => logs data for all events
The on
method returns a subscription object that can detach the handler using the dispose method, and can also be used to replay events currently in the event array:
subscription.dispose()
// => detaches the event handler
subscription.replay()
// => calls the handler for all events currently in uv.events
Note
Subscriptions that have been disposed will not call the handler when replay is called. |
Note
On Single Page Applications that emit multiple |
Once
uv.once(type, handler, [context])
Attaches an event handler that will be called once, only 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. 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:
uv.once('ecProduct', function (data) {
console.log(data)
})
emit('ecProduct')
// => logs data
emit('ecProduct')
// => does not log
The once
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:
subscription.dispose()
// => detaches the event handler
subscription.replay()
// => calls the handler for all events currently in uv.events
Note
Subscriptions that have been disposed will not call the handler when replay is called. |
Note
On single-page applications that emit multiple |
Emit
uv.emit(type, [data])
Emits an event with the type and data specified.
The data should conform to the schema for the event type emitted.
All events that are emitted are given a meta
property with the event type
:
uv.emit('ecProduct', {
product: {
id: '112-334-a',
price: 6.99,
name: '18th Birthday Balloon',
category: ['Party Accessories', 'Birthday Parties']
},
color: 'red',
stock: 6,
eventType: 'detail'
})
// => emits an ecProduct event
The emitted event will have meta data attached:
{
"meta": {
"type": "ecProduct"
},
"product": {
"id": "112-334-a",
"price": 6.99,
"name": "18th Birthday Balloon",
"category": ["Party Accessories", "Birthday Parties"]
},
"color": "red",
"stock": 6,
"eventType": "detail"
}
Events
The events array is a cache of events emitted since the last page load. By iterating over the array, it is possible to interpret the visitor journey or the current state of the page.
getMemberships
Returns a promise that resolves to the array of Qubit segments Ids that the visitor is a member of:
module.exports = function triggers (options) {
return options.getMemberships().then((segments) => {
return {
execute: segments.includes('SG-2499-a2i8sn')
}
})
}
Note
This method will only work if Segments is enabled for your property. |
isMemberOf
A more convenient method for checking if the visitor is in a specific segment. Returns a promise that resolves with a boolean, which is true if they are a member of the segment and false if not:
module.exports = function triggers (options) {
return options.isMemberOf('SG-2499-a2i8sn').then((isMember) => {
return {
execute: isMember
}
})
}
Note
This method will only work if Segments is enabled for your property. |
onMembershipsChanged
This method allows you to subscribe to Qubit segment membership changes. This is useful for doing advanced triggering logic based on segments, or for syncing Qubit segments to a third party. It returns a subscription object with a dispose method that you can use in order to unsubscribe:
module.exports = function triggers (options) {
const subscription = options.onMembershipsChanged(({ segments, changeset }) => {
// `segments` lists the segment IDs that the user is now a member of
console.log(segments)
// changeset contains the segment IDs that the user joined and left
console.log(changeset)
})
// It is important to dispose of your subscription when appropriate
options.onRemove(() => subscription.dispose())
return true
}
Note
This method will only work if Segments is enabled for your property. |
onRemove
This hook lets you register any cleanup functions such as removing event listeners, which will be called if Smartserve restarts. This is particularly important in a single page application (SPA), as it allows you to prevent side effects carrying over between virtual page views.
If you implement this method, you will also be able to use the hot reloading feature of Coveo Qubit CLI.
module.exports = function triggers (options) {
options.onRemove(cleanup)
return true
}
module.exports = function variation (options) {
options.onRemove(cleanup)
}
onActivation
This hook allows you to register callbacks that will fire when an experience activates, even if the visitor is allocated to the control group. This can be useful for sending analytic events:
module.exports = function triggers (options) {
options.onActivation(trackExperience)
return true
}
react
This object exposes methods for interacting with Qubit’s React integration. See Integrating With React Sites for more information.