Installation
No NPM package yet. The Live Extractor can be imported by adding: |
{
"dependencies": {
...,
"zelros-live-extractor": "zelros/zelros-live-extractor#master"
}
}
to your package.json
Or simply by building the library (see instructions below) and inserting a <script src="/path/to/zelros-live-extractor.js"></script> tag.
You can also serve the generated source map (zelros-live-extractor.js.map) for easier debugging.
Use
If LiveExtractor was inserted via a script tag, you can use the SDK like this:
const liveExtractor = new window.ZelrosLiveExtractor(config);
Otherwise do:
const LiveExtractor = require('zelros-live-extractor');
const liveExtractor = new LiveExtractor(config);
Configuration
The SDK requires a config object looking like this:
const config = {
username: '12345A', // Specify this option only if you're using autologin on the assistant (deprecated)
roomId: 'AZ3456TGY78IUJHGT54EDFGY7IK', // Specify this option if you have a good reason to override the ID of the room shared with the assistant (see below)
baseURL: 'http://insurance-dev.zelros.com:8080',
openingMode: 'popup',
popupOptions: {
name: 'zelros',
position: {
top: 50,
left: 50,
width: 400,
height: 700,
},
},
onStateChange: function(states) {
console.log('Assistant state changed from', states.previousState, 'to', states.currentState);
},
transportOptions: { // You can tune these depending on your network
connectionTimeout: 2000,
assistantPresenceTimeout: 5000,
assistantLaunchTimeout: 10000,
},
logging: false,
onMessage: function(message) {
console.log('Message from assistant', message);
},
};
Property |
Required |
Description |
username |
false |
The name (or any uniquely identifying property) of the connected user in the CRM |
baseURL |
true |
The baseURL of your tenant |
openingMode |
false |
Can be "none" (default), "popup", "tab" or "custom" (see below) |
popupOptions |
false |
Position and name options for the popup if openingMode is "popup" |
onOpen |
false |
Function called when the assistant needs to be opened in a "custom" way |
onStateChange |
false |
Function called when the state of the assistant is sent from the assistant to the SDK |
transportOptions |
false |
Options for the underlying socket.io transport. To be tuned depending on your corporate network bandwidth, how long is it acceptable to wait, etc. |
logging |
true |
Set to false if you want to mute internal console logs and errors |
roomId |
false |
Override the ID of the shared room that will be used by the SDK and the assistant |
onMessage |
false |
Function called when a message is sent from the assistant to the SDK |
Opening mode
When using openingMode: "none", the SDK considers that the assistant has already been opened by something else. Maybe the assistant is in an iframe somewhere or maybe it has been opened by a previous page of the CRM.
When using openingMode: "popup", the SDK is responsible for opening the assistant. When detecting that the assistant should be opened (could not establish a connection with an existing assistant), it opens a popup with window.open(…) and uses the popupOptions to determine the initial size and position of the popup. Some browser, when in full screen, open a new tab instead of a popup.
When using openingMode: "tab", the the SDK is responsible for opening the assistant. When detecting that the assistant should be opened (could not establish a connection with an existing assistant), it opens a new tab with window.open(…, '_blank').
When using openingMode: "custom", the SDK calls the onOpen callback with the URL of the assistant. The callback is then responsible for opening the assistant itself. It may check additional conditions, try to open the assistant in another application by transforming the URI scheme, etc. It’s an initialization error to specify openingMode: "custom" without also providing a onOpen callback.
Example:
var config = {
...,
openingMode: 'custom',
onOpen: function(url) {
url = url.replace('https://', 'firefox://'); // Somehow you have a custom URI scheme handler that opens Firefox instead of current browser
window.open(url);
},
};
Initialization
The SDK requires an initialization phase during which:
It establishes the connection with the Zelros service responsible for passing messages between an external script and the assistant It establishes the communication with the assistant via the Zelros messaging service Or it opens the assistant if not opened yet and tries 2. again To initialize the SDK do:
liveExtractor.init((err) => {
if (err) {
return console.error(err);
}
// We can start sending messages to the assistant
// Do some stuff...
});
or
try {
await liveExtractor.init();
// We can start sending messages to the assistant
} catch (e) {
console.error(err);
}
One can also check if the SDK is ready at a later date with the boolean liveExtractor.ready flag:
// Later, somewhere else in your application
if (liveExtractor.ready) {
// Do some other stuff
}
Checking presence of the assistant
At any time, the SDK can be used to check if the assistant’s page is already open or still open like this:
try {
const presence = await liveExtractor.isAssistantPresent();
console.log('Assistant is', presence ? 'present' : 'NOT present');
} catch (e) {
console.error(err);
}
or with a callback:
// liveExtractor.isAssistantPresent(onResolve, onReject)
liveExtractor.isAssistantPresent((err, presence) => {
if (err) {
// An error occurred during the check of the presence, typically a failed connection to the messaging service
return console.error(err);
}
console.log('Assistant is', presence ? 'present' : 'NOT present');
});
Usage
Once the SDK is initialized, the JS script can start sending messages / events to the assistant.
Basic
The very first message should be to indicate to the assistant on which customer the CRM is positioned:
// Send the ID of the current customer
liveExtractor.selectCustomer('123');
Then, you can send arbitrary data to the Zelros platform with:
// Send some arbitrary payload
liveExtractor.sendData({ foo: 'bar', baz: true });
Navigation
You can also drive the navigation inside the assistant (whether the assistant should display the recommendations or wait, etc.) like this:
/**
* Position the assistant on customer "123" but stays on customer landing page
* instead of displaying recommendations immediately which is the default behavior
*/
liveExtractor.selectCustomer('123', { page: 'customer:home' });
or if assistant is already positioned on the customer:
liveExtractor.navigate('customer:home');
The assistant can navigate to the following sections:
-
"home": the landing page of the assistant, no customer is selected
-
"customer:home": a customer page that doesn’t display the recommendations yet
-
"customer:recommendations": a customer page that displays the recommendations to help the advisor during the rebound phase
-
"customer:quote": a customer page that helps the advisor during the quote edition phase
Tracking
To help us better understand the usage of the assistant, the SDK can send tracking events like this:
liveExtractor.trackEvent('event_name', { customerId: currentState.customerId, foo: 'bar', baz: true });
Here is the list of the standard event names and their meanings but you can send any type of event.
Event name |
Description |
display_assistant |
This event is automatically sent by the SDK when it’s its responsibility to open the assistant (openingMode = "popup" or "tab"). If the display of the assistant is controlled by some custom mechanism, you can also send this event. |
hide_assistant |
If the display/hiding of the assistant is controlled by a custom mechanism, you can tell us when the assistant is hidden |
open_notification |
This type of events is already sent by the assistant when a HTML5 notification is clicked. But if you display yourself some kind of notification that triggers the display of the assistant, you can send these events too |
close_notification |
This type of events is already sent by the assistant when a HTML5 notification is discarded. But if you display yourself some kind of notification that triggers the display of the assistant and they can be discarded, you can send these events too |
Receiving messages from the assistant
If you expect to receive messages back from the assistant, you need to either pass the onMessage callback option like this:
var config = {
...,
onMessage: function(message) {
console.log('Message topic', message.topic);
console.log('Message payload', message.payload);
},
...
};
or listen to the "message" event like this:
liveExtractor.on('message', function (message) {
console.log('Message topic', message.topic);
console.log('Message payload', message.payload);
});
Tracking the state of the assistant
If you need to track the state of the assistant (check the number of recommendations, check if there is a quote or not, etc.), you can do it like this:
var config = {
...,
onStateChange: function(states) {
console.log('Assistant state changed from', states.previousState, 'to', states.currentState);
},
...
}
or listen to the "state_change" event like this:
liveExtractor.on('state_change', function (states) {
console.log('Assistant state changed from', states.previousState, 'to', states.currentState);
});
A state has the following structure:
var state = {
customer: { ... } | null,
recommendations: [..., ...],
currentQuote: { ... } | null,
};
Advanced
Under the hood, messages are sent through topics. The following supported topics are:
-
"customer": to notify the assistant about which customer is displayed on the CRM
-
"customer_profile": to perform atomic updates on the customer profile loaded on the assistant (for instance, customer changed his/her marital status in the CRM)
-
"quote", "quote_update", "quote_reset": to notify the assistant about the start, update or end of the edition of a quote
-
"decision": to notify the assistant about the choice of the customer to start a quote
If you want fine grain control over the retry policy of the messages on the messaging server or help Zelros processing the messages by already sending them in the right format, you have to use topics.
For instance, the equivalent of liveExtractor.selectCustomer('123') is:
const customerTopic = liveExtractor.createTopic('customer', 'last');
customerTopic.send({ customerExternalId: '123' });
Then, once the assistant knows about the customer, the script can send over events like this:
/**
* Send customer profile updates
* Refer yourself to the Standard Data Model to find how to override a specific property in the structure
*/
const customerProfileTopic = liveExtractor.createTopic('customer_profile', 'none');
customerProfileTopic.send({ foo: 'bar' });
You should avoid creating topics and trying to send messages through them if the SDK is not yet initialized or failed to initialize correctly.
Build
-
Clone this repo
-
Install the dependencies with npm install
-
Run npm run build
-
Retrieve the zelros-live-extractor.js and zelros-live-extractor.js.map file in the build folder
You can minify the script by passing the NODE_ENV environment variable to "production".
If you use IntelliJ, there are 2 ready-to-use run configs: "build" and "build:prod".
How it works
To be able to communicate with each other, the SDK and the assistant both connects to a "messaging" server. Each party establishes a bi-directional socket.io connection (either websocket if possible or long-polling) between it and the server.
To be able to exchange messages, each party has to provide the same unique ID and this ID will become the identifier of the shared socket.io room they will be assigned to. Within this room, any message coming from a socket will be re-emitted to other sockets in the room.
There are multiple strategies to come up with a shared ID between the SDK and the assistant:
Cookie-based room ID
This is the preferred way and it always works unless the CRM in which the SDK is used and the assistant don’t share cookies.
With this strategy, there is nothing to do on the SDK or the assistant side:
the "messaging" service sets a random httpOnly cookie on its domain on first request any future request from the SDK or from the assistant will include this cookie the "messaging" service will know the room they belong to
User-provided room ID
In situations where the CRM in which the SDK is used and the assistant don’t share cookies (CRM opened in custom browser, assistant opened in Internet Explorer for instance), this is the preferred way.
It still requires both parties to agree beforehand on a shared ID. It may be an ID of the workstation accessible in JS, a session ID, etc.
By passing the roomId when initializing the SDK, the SDK will try to use both the cookie-based room ID and the specified roomId.
When using this strategy, you have to make sure that Zelros made the evolutions on the assistant side to support your specific situation and use the same ID.
Room ID derived from the username
This is the least preferred way to agree on a shared ID and should only be used during early development phases or in a network environment considered safe from intruders or eavesdroppers.
With this strategy, the SDK and the assistant both derive the ID of the room from the username of the connected user.
When using this strategy, the SDK will try to use both the cookie-based room ID and the ID derived from the username.