Web SDK Installation

We recommend running our examples to get started. Click the link below to download zipped files.

Web SDK v.2 examples files

In order to get the Web SDK up and running you must:

  1. Include the Web SDK Loader in your web client

  2. Initialize the Web SDK with your COMPANY_KEY

  3. Initialize authentication with your COMPANY_SECRET using your backend code

Installation Workflow

Getting Started

Include the Web SDK Loader in Webpage

  • Include the Web SDK Loader Javascript library in your webpage:

    <!-- IN YOUR WEB PAGE --> <script src="https://websdk.ujet.co/v2/loader.js"></script>
    
  • Import the module in your project:

    import UJETKit from '@ujet/web-sdk'

Initialize the web SDK

You can initialized the web SDK using your company key.

Get your company key

To get your company key, follow these steps:

  1. Sign into the Contact Center AI Platform (CCAI Platform) portal using administrator credentials.

  2. Click Menu, and then click Settings > Developer settings.

  3. Go to the Company key and secret code pane and save the code in the Company key field.

You can then initialize the Web SDK with the new UJET(config) method and ujet.on('created', function) event. If your Admin Portal is https://company.example.com, then the host is https://company.api.example.com:

// INITIALIZE WEB SDK
var ujet = new UJET({
  companyId: "YOUR_COMPANY_ID",
  host: "https://ujetcompany.api.ujet.co",
});

ujet.on('created', function () {
  ujet.authenticate(getAuthToken);
});

Alternatively, you can use authenticate option without created event:

var ujet = new UJET({
  companyId: "YOUR_COMPANY_ID",
  authenticate: getAuthToken,
  host: "https://ujetcompany.api.ujet.co",
});

where getAuthToken() is a function that calls upon a JWT signing mechanism from your backend:

function getAuthToken() {
// YOU SHOULD HAVE THIS KIND OF API ON YOUR SERVER return fetch('/auth/token')
.then(function(resp) {
// { token: '....' } return resp.json();
});
}

where fetch() calls upon a JWT signing mechanism from your backend (for additional information, click here).

Optional: Initialize the web SDK for co-browse

To use co-browse, you need to provide the co-browse domain and license key of your CCAI Platform instance during SDK initialization.

To initialize the web SDK for co-browse, follow these steps:

  1. To get the co-browse domain and license key of your CCAI Platform instance, do the following:

    1. Sign into the CCAI Platform portal using administrator credentials.

    2. Click Menu, and then click Settings > Developer settings.

    3. Go to the Co-browse pane and click the toggle to the on position.

    4. Save the values in the Co-browse domain and License key fields.

  2. To provide the co-browse domain and license key during SDK initialization, include the following code when you Initialize the web SDK:

    var ujet = new UJET({
      // other options
      cobrowseOptions: {
        license: "LICENSE_KEY",
        trustedOrigins: ["CO-BROWSE_DOMAIN"],
        api: "CO-BROWSE_DOMAIN"
      },
      // other options
    })
    

    Replace the following:

    • LICENSE_KEY: the license key that you saved in the previous step

    • CO-BROWSE_DOMAIN: the co-browse domain that you saved in the previous step

For more information see Configure co-browse.

Initialize authentication with Company Secret

The function getAuthToken() should call your API and encode your payload with your COMPANY_SECRET.

Here is an example of a JWT signing using ExpressJS:

const express = require('express')
const jwt = require('jsonwebtoken')

const port = process.env.PORT || 3000
const secret = process.env.COMPANY_SECRET || 'secret'

const app = express()

app.use(express.json())

app.post('/auth/token', function (req, res) {
const payload = {}
payload['iss'] = 'YOUR_COMPANY_NAME'
const iat = parseInt(Date.now() / 1000, 10)
payload['iat'] = iat
payload['exp'] = iat + 600
const token = jwt.sign(payload, secret, { algorithm: 'HS256' })
res.json({ token })
})

app.listen(port, function () {
console.log(`Listing at http://localhost:${port}`)
})

You can use any backend service.

Content Security Policy

If your production server has content security policy, add:

https://websdk.ujet.co/

into your script-src and frame-src.

Support for Internet Explorer 11

To support Internet Explorer, babel-polyfill is used in our code. If your website also uses babel-polyfill, do not import it to the Web SDK as using the same library globally and in the Web SDK could cause an exception. Before importing the package, we recommend adding code to check for this and to help prevent this.

Keeping Track of Users (Recommended)

The above example will not keep track of users. If you would like to identify repeat users in your CRM and/or use pre-canned responses with the users' information, you must add identifiers to users.

To do this you must add identifiers in the following places:

  1. Pass to backend in getAuthToken()

    function getAuthToken() {
    // YOU SHOULD HAVE THIS KIND OF API ON YOUR SERVER return fetch('/auth/token', {
    headers: {
    'Content-Type': 'application/json'
    },
    method: "POST",
    body: JSON.stringify({
    payload: {
    identifier: 'test@email.com',
    name: 'Test user',
    email: 'test@user.com',
    phone: '1800UJETSDK'
    }
    });
    }).then(function(resp) {
    return resp.json();
    });
    }
    
  2. Add to payload when encoding JWT

    const express = require('express')
    const jwt = require('jsonwebtoken')
    
    const port = process.env.PORT || 3000
    const secret = process.env.COMPANY_SECRET || 'secret'
    
    const app = express()
    
    app.use(express.json())
    
    app.post('/auth/token', function (req, res) {
    const payload = req.body.payload
    payload['iss'] = 'YOUR_COMPANY_NAME'
    const iat = parseInt(Date.now() / 1000, 10)
    payload['iat'] = iat
    payload['exp'] = iat + 600
    const token = jwt.sign(payload, secret, { algorithm: 'HS256' })
    res.json({ token })
    })
    
    app.listen(port, function () {
    console.log(`Listing at http://localhost:${port}`)
    })
    
  3. Add extra options in authentication()

    new UJET({
    // ...
    authenticate: function() {
    return getAuthToken().then({ token } => {
    return {
    token: token,
    user: {
    identifier: YOUR_UNIQUE_USER_ID,
    name: 'Test user' //optional,
    email: 'test@user.com', //optional,
    phone: '000000000' //optional
    }
    };
    });
    },
    })
    

External Chatbot Transfer (Optional)

When you transfer a chat from the virtual agent to the agent, you can override the greeting message and pass the transcripts to the agent by backfilling the external_chat_transfer field to the custom data. The greeting_override supports Markdown formatting.

{
"external_chat_transfer": {
"greeting_override": "Please hold while we connect you with a human agent.",
"agent": {
"name": "Agent Name",
"avatar": "https://ujet.s3.amazonaws.com/default-virtual-agent-avatar-1.png"
},
"transcript": [
{
"sender": "agent",
"timestamp": "2021-03-15 12:00:00Z",
"content": [
{
"type": "text",
"text": "Hello! How can I help you today?"
},
{
"type": "buttons",
"buttons": [
{
"label": "Create New Order",
"selected": false
},
{
"label": "Check Order Status",
"selected": true
},
{
"label": "Check Account Balance",
"selected": false
},
]
}
]
},
{
"sender": "end_user",
"timestamp": "2021-03-15 12:00:15Z",
"content": [
{
"type": "text",
"text": "Check Order Status"
}
]
},
{
"sender": "agent",
"timestamp": "2021-03-15 12:00:16Z",
"content": [
{
"type": "text",
"text": "I can help you with that, what's your order number?"
}
},
{
"sender": "end_user",
"timestamp": "2021-03-15 12:00:20Z",
"content": [
{
"type": "media",
"media": {
"type": "image",
"url": "https://ujet.s3.amazonaws.com/default-virtual-agent-avatar-1.png"
}
}
}
]
}
}

Chat Custom Data (Optional)

When a chat is started, custom data can be sent with the chat object. Custom data can be anything from OS, Version, location, or any other data that may be relevant to the respective chat.

var ujet = new UJET({
... // other parameters
customData: {
version: {
label: 'Version',
value: '1.1.0'
},
platform: {
label: 'Platform',
value: navigator.platform
}
},
});

The custom data format is similar to a JSON object and contains key, label and value. e.g.

{
k1: {
label: 'Version',
value: '1.2.3'
},
k2: {
label: 'Dashboard',
value: 'http://example.com'
}
}

key is a unique identifier for data. In the above example, k1 k2 are keys.

label is the display name on the CRM page. value is the value of the label.

Disable Attachments (Optional)

You can stop consumers from uploading attachments with the disableAttachment option:

new UJET({
// ...
disableAttachment: true
});

With disableAttachment: true, there will be no attachment icon in the chat input area and consumers can not drag and drop files into the message area.

Chat Deflection (Optional)

When agents are not available, you can specify options for automatically handling this condition.

Options for chat deflection can be found in the CCAI Platform Portal, at Settings > Chat > In-App & In-Web Deflection.

Chat Deflection Setting

Multiple Language and Visual Message Customization (Optional)

The new CCAI Platform (option) method has two fields to support multiple languages and visual message customization:

  • lang: This indicates the default language when the consumer did not choose a preferred language. This code conforms to ISO 639-1 and if omitted, is en by default.

  • translation: The CCAI Platform Web SDK supports multiple languages for displayed texts. With the translation object, you can customize texts for existing language or even add texts for new languages. For example: de, es, fr, ja.

The following is an example of a translation object which is customizing English copy. As you can see, the top level keys of the translation object should be the language code.

// ES6 let translation = `{
"en": {
"ujet_start_title": "Hi!"
},
"es": {
"ujet_start_title": "¡Hola!"
},
"fr": {
"ujet_start_title": "Salut!"
},
"de": {
"ujet_start_title": "Hallo!"
},
"it": {
"ujet_start_title": "Ciao!"
},
"ja": {
"ujet_start_title": "こんにちは!"
},
"ko": {
"ujet_start_title": "안녕하세요!"
},
"pt": {
"ujet_start_title": "Olá!"
},
"pt-BR": {
"ujet_start_title": "Olá!"
},
"sv": {
"ujet_start_title": "Hej!"
}

}`;

// initialize when dom ready var ujet = new UJET({
... // other fields
lang: 'en',
translation: translation;
});

The customization messages are:

"ujet_ask_phone_number_button_title": "Call Me"
"ujet_ask_phone_number_description": "Provide your phone number below"
"ujet_ask_phone_number_title_instant": "We'll Call You"
"ujet_ask_phone_number_title_scheduled": "Let's Schedule a Call"
"ujet_ask_phone_number_warning": "Your call may be monitored or recorded for training and quality assurance purposes."
"ujet_call_confirm_content": "Your phone should be ringing right about - {0}"
"ujet_call_confirm_start_new_conversation": "Start A New Conversation"
"ujet_call_record_permission_subtitle": "Do you give permission for {0} to record your call for training and quality?"
"ujet_call_record_permission_title": "Permission to Record"
"ujet_channel_chat": "Let's connect you to one of our chat support specialists",
"ujet_channel_instant_call": "Let one of our support specialists give you a call now",
"ujet_channel_menu_chat": "Chat now"
"ujet_channel_menu_email": "Email"
"ujet_channel_menu_instant_call": "Call now"
"ujet_channel_menu_keep_waiting": "Keep Waiting"
"ujet_channel_menu_scheduled_call": "Schedule call"
"ujet_channel_scheduled_call": "Let's schedule a time for a support specialist to call and help you",
"ujet_channel_email": "Please send us an email so we can help",
"ujet_chat_end": "End chat"
"ujet_chat_ended": "This chat has ended"
"ujet_chat_input_placeholder": "Type your message here"
"ujet_chat_leave": "Leave chat"
"ujet_chat_timed_out": "This chat has timed out"
"ujet_chat_title_with_multiple_agent": "Multiple Agents"
"ujet_chat_title_with_one_agent": "Chatting with {0}"
"ujet_chat_title_with_two_agent": "Chatting with {0} & {1}"
"ujet_chat_transfer_failed": "Transfer has failed"
"ujet_chat_transfer_joined": "<b>{0}<\/b> just joined the conversation"
"ujet_chat_transfer_left": "<b>{0}<\/b> just left the conversation"
"ujet_chat_transfer_started_menu": "<b>{0}<\/b> is transferring this chat to another agent..."
"ujet_chat_transfer_started_user": "<b>{0}<\/b> is adding another agent to this conversation..."
"ujet_common_back": "Back"
"ujet_common_cancel": "Cancel"
"ujet_common_end": "End"
"ujet_common_no": "No"
"ujet_common_save": "Save"
"ujet_common_submit": "Submit"
"ujet_common_support": "Support"
"ujet_common_yes": "Yes"
"ujet_deflection_menu_title": "Select from the options below"
"ujet_error_no_available_language": "No Available Language"
"ujet_error_phone_number_invalid": "Please input a valid phone number."
"ujet_file_upload_button": "Choose a file to upload"
"ujet_file_upload_failure_size": "Looks like we couldn't upload. <br> Please try uploading a file <br> that is less than {0}."
"ujet_file_upload_failure_type": "Looks like we couldn't upload. <br> We only accept <br> .JPG, .PNG, or .MP4."
"ujet_file_upload_failure_unknown": "Looks like we couldn't upload. <br> Please try again!"
"ujet_file_upload_subtitle": "Drop files here to upload"
"ujet_file_upload_title": "Upload Files"
"ujet_greeting": "Hi there, how can we help?"
"ujet_instant_call_confirm_content": "Your phone should be ringing shortly"
"ujet_language_chinese": "中文"
"ujet_language_english": "English"
"ujet_language_french": "Français"
"ujet_language_german": "Deutsch"
"ujet_language_italian": "Italiano"
"ujet_language_japanese": "日本語"
"ujet_language_korean": "한국어"
"ujet_language_portuguese": "Português (Portugal)"
"ujet_language_portuguese_brazil": "Português (Brazil)"
"ujet_language_spanish": "Español"
"ujet_language_swedish": "Svenska"
"ujet_menu_title": "Select an option"
"ujet_message_back_in_menu": "Looks like you changed your mind! How else can we help?"
"ujet_message_channel": "How would you like to communicate?"
"ujet_message_chat_deflection_afterhour": "We are currently closed. We look forward to helping you during our normal business hours."
"ujet_message_chat_deflection_default": "We are currently experiencing a high volume of requests with a current wait time of <b>{0}<\/b>. How would you like to reach out?"
"ujet_message_chat_deflection_email": "Please contact us via email: <b><a href="mailto:{0}">{0}<\/a><\/b>."
"ujet_message_chat_deflection_keepwaiting": "Thank you for continuing to wait. The remaining wait time is <b>{0}<\/b>."
"ujet_message_chat_deflection_outage": "We are currently experiencing a high volume of request, how would you like to reach out?"
"ujet_message_chat_deflection_recurring": "Thanks for your patience! The remaining wait time is <b>{0}<\/b>."
"ujet_message_chat_restart": "Connecting to your ongoing chat, one moment please..."
"ujet_message_chat_start": "One moment please..."
"ujet_message_queue": "Let's help you with<br /><strong>{0}<\/strong>"
"ujet_rating_feedback_placeholder": "Let us know how we can improve."
"ujet_rating_result_subtitle": "We appreciate your feedback"
"ujet_rating_result_title": "Thank you!"
"ujet_rating_title": "Rate Your Experience"
"ujet_redirect_action_title": "Open this page in a new tab"
"ujet_redirect_url_title": "Visit the page below"
"ujet_schedule_time_description": "Pick a time that works best for you"
"ujet_schedule_time_title": "Let's Schedule a Call"
"ujet_scheduled_call_cancel_cancel": "Cancel"
"ujet_scheduled_call_cancel_content": "You scheduled a support call for<br><b>{0}<\/b> at <b>{1}<\/b>."
"ujet_scheduled_call_cancel_keep": "Keep It"
"ujet_scheduled_call_cancel_title": "Cancel the existing call?"
"ujet_screenshot_init_cancel": "No Thanks"
"ujet_screenshot_init_okay": "Accept"
"ujet_screenshot_init_title": "Screenshot Request"
"ujet_screenshot_install_cancel": "Cancel"
"ujet_screenshot_install_okay": "Install"
"ujet_screenshot_install_title": "Install Chrome Extension"
"ujet_screenshot_take_action": "Take Screenshot"
"ujet_screenshot_take_title": "Click the button below to send a screenshot to the agent"
"ujet_screenshot_verify_cancel": "No"
"ujet_screenshot_verify_okay": "Yes"
"ujet_screenshot_verify_title": "Successfully Installed Chrome Extension"
"ujet_start_title": "Need any help?"
"ujet_tap_to_minimize": "Tap to minimize"
"ujet_time_hour": "hour | hours"
"ujet_time_minute": "minute | minutes"

Logo and Icon Customization (Optional)

new UJET(option) method has some fields to support logo and icon customization.

  • logo: The url of the logo image

  • The position of the widget (Only applies desktop)

    • right: Sets the right edge position in px (Default value is 50)

    • bottom: Sets the bottom edge position in px (Default value is 50)

  • The position of the icon (Only applies desktop)

    • right: Sets the right edge position in px (Default value is 50)

    • bottom: Sets the bottom edge position in px (Default value is 50)

Example of Logo and Icon Customization

new UJET({
logo: 'https://example.com/logo.svg',
// widget position
right: '50px',
bottom: '150px',

// launcher position
launcher: {
right: '50px',
bottom: '50px',
}
})

Logo and Icon Customization

Logo and Icon Customization

Theme Customization (Optional)

The new UJET(option) method has a field to support theme customization.

  • style: The theme object supports fours values for the widget.

    • links: A list of stylesheet links for web fonts

    • --primary-font: A value for the font-family css style applied to the entire Web UI e.g. Merriweather

    • --primary-color: A hexcode value used as the primary color of the Web UI e.g. #51C3C3

    • --link-color: A hexcode value used as the link color of the Web UI e.g. #51C3C3

  • launcher:: The launcher object supports four values for the launcher.

    • cssText: A css syntax used as the css style for the launcher

    • chatIcon: A svg icon url used for the normal chat icon

    • closeIcon: A svg icon url used for the close icon

    • style: This separated theme object supports two values for the launcher.

      • --background-color: A hexcode value used as the background color of launcher e.g. #E85230 --icon-color: A hexcode value used as the icon color of the launcher icon e.g. #FFF

    var ujet = new UJET({ // ... style: { links: [ 'https://fonts.googleapis.com/css?family=Droid+Serif:400,700&display=swap', ], '--primary-font': 'Droid Serif,Georgia,serif', '--primary-color': '#F1684A', '--link-color': '#F1684A', }, launcher: { cssText: '.wrap button{background:#E85230}', chatIcon: 'https://example.com/logo.svg', closeIcon: 'https://example.com/close.svg', style: { '--background-color': '#F1684A', '--icon-color': '#fff', } } });

Tracking Channel Selection and Email Submission (Optional)

To allow tracking of channel selection and email submission, the Web SDK uses the postMessage function which passes a message with the following data: * application: The device type * sdk_version: The version of the WebSDK currently in use (e.g 1.17.3) * user_agent: The browser version * company: The tenant name * menu_name: The name of the queue/menu that the consumer has selected * menu_path: The path to the queue/menu that the consumer has selected * menu_id: The Menu ID of the queue/menu that the consumer has selected * url: The URL of the web page that the consumer was on when they made a channel selection/submitted an email * timestamp: The time that the consumer made their selection * has_attachments: Whether or not an email had attachments when it was submitted (this only appears during email submission, not during channel selection)

Message data is stored in a ujet object with 2 attributes: one called action that will be a string containing the name of the action completed, one called data that will include the data described above.

To retrieve data from the message, you can create an event listener listening for "message". A simple example that will print the action and data to the console is outlined below. A working example can be found in the tracking-channel-selection folder.

window.addEventListener('message', (e) => {
if (e.data && e.data.ujet) {
console.log(`Action: ${e.data.ujet.action}`)
console.log(`Message Data: ${e.data.ujet.data}`)
}
})

Hiding the Agent Logo Border

To hide the Agent Logo Border, add the '--logo-shadow': 'none' in the style attribute and set it to true in new UJET(option):

new UJET({
// ...
style: {
'--logo-shadow': 'none',
}
})

Hiding the Launch Icon (Optional)

For aesthetic reasons, you may wish to hide the Web UI launch icon, opting to instead use a Proactive Chat Trigger or to start the chat programmatically. To remove the launch icon, add the launcher attribute and set it to true in new UJET(option):

new UJET({
// ...
launcher: false,
})

To programmatically start the Web UI, see the Programmatically starting the Web UI (Optional) section above. You can also reference the example in the tracking-channel-selection folder. To start the Web UI with a Proactive Chat Trigger, see the Proactive Chat (Optional) section above.

Using a Direct Access Point (Optional)

You can set it up so that the consumer will jump to a specific queue in the queue structure via Direct Access Points.

First you need to create a Direct Access Point in the Admin Portal.

  1. Go to Settings > Queue.

  2. Turn on Use for the In-Web menu and go to EDIT / VIEW.

  3. Select any queue from the queue structure.

  4. Click Create direct access point.

  5. Access Point type = General.

  6. Add input data for the direct access point in the dialog.

  7. Click CREATE.

You can pass the name of a direct access point through the ujet.start(options) method:

var launcher = document.getElementById('launcher');
launcher.addEventListener('click', function() {
if (ujet.status === 'open') {
ujet.close();
} else {
ujet.start({ menuKey: '__MENU_KEY__' });
}
});

Programmatically closing the Web UI (Optional)

This is an optional step. Without this step, the Web UI will be finished and minimized by itself.

This step allows you to call the callback function when the consumer wants to close the Web SDK.

ujet.on('close', function() {
// do something here
});

Programmatically starting the Web UI (Optional)

This is an optional step. Without this step, consumers can start the Web UI by clicking the Web UI launch icon.

This step allows you to open the Web UI programmatically with the ujet.start(options) method. You may want the consumer to click an additional button to open the Web UI like this:

<button id="launcher">Click to open</button>

var ujet = new UJET({
companyId: "YOUR_COMPANY_ID",
host: "HOST_URL",
launcher: false
});

var launcher = document.getElementById('launcher');
launcher.addEventListener('click', function() {
if (ujet.status === 'open') {
ujet.close();
} else {
ujet.start();
}
});

ujet.on('ready', function() {
launcher.textContent = 'ready to talk';
});

ujet.registerHook('loading', function () {
launcher.textContent = 'loading';
});

ujet.registerHook('open', function () {
launcher.textContent = 'Click to close';
});

ujet.registerHook('close', function () {
launcher.textContent = 'Click to open';
});

ujet.on('created', function () {
ujet.authenticate(getAuthToken);
});

You can also close the widget with ujet.close() method, and you can remove the widget with ujet.destroy() method.

Proactive Trigger (Optional)

Proactive Triggers make it possible to trigger the Web SDK to send a message to consumers proactively.

For now we don't have any Javascript API for this; however, you can use Proactive Chat by setting up Proactive Chat triggers.

You can set up Proactive Chat triggers in Settings > Chat > Web Proactive Chat Triggers from the Admin Portal.

Existing Ticket IDs

If you have an existing ticket for a consumer, you can retrieve the ticket ID from your CRM and pass it into the WebSDK by calling ujet.start(). For example:

yourFunctionToRetrieveTicket()
.then((existingTicket) => {
ujet.start({ ticketId: existingTicket });
});

You can refer to the example in the ticket-id folder for reference.