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:

  1. "customer": to notify the assistant about which customer is displayed on the CRM

  2. "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)

  3. "quote", "quote_update", "quote_reset": to notify the assistant about the start, update or end of the edition of a quote

  4. "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

  1. Clone this repo

  2. Install the dependencies with npm install

  3. Run npm run build

  4. 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".

Demo

There is a basic example of SDK usage in the demo folder.

Just serve the demo/index.html

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:

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.