@bandyer/bandyer-chat-widget

Bandyer widget chat is a fast and effective way to offer live chat and videochat in your application.

Usage no npm install needed!

<script type="module">
  import bandyerBandyerChatWidget from 'https://cdn.skypack.dev/@bandyer/bandyer-chat-widget';
</script>

README

BANDYER CHAT WIDGET

Bandyer widget chat is a fast and effective way to offer live chat and videochat in your application.

Consuming a library

You can consume the library from NPM:

npm install @bandyer/bandyer-chat-widget

For browser you can also use the version from CDN:

<script src="https://cdn.bandyer.com/sdk/js/chat/X.X.X/bandyer-widget.min.js" type="text/javascript" ></script>

Example embed in HTML page;

<html>
<head></head>
    <body>
    <script src="https://cdn.bandyer.com/sdk/js/chat/1.45.0/bandyer-widget.min.js" type="text/javascript" >
    </script>
    </body>
</html>

The widget attaches in the window object of the HTML page the BandyerChat global variable.

Browser support

Browser min version Plugin requested
Chrome 56 Screenshare extension for Chrome <72
Firefox 54
Safari 12
Edge old 17
Edge new 79
Internet Explorer 11 Temasys WebRTC Plugin for Call

Versions

Latest version available is: 1.45.0 https://cdn.bandyer.com/sdk/js/chat/1.45.0/bandyer-widget.min.js

For the complete list of versions visit: CHANGELOG

Screenshots

Drawing Drawing
Drawing Drawing
Drawing Drawing

Create

.create()

const Client = await BandyerChat.create({
 
    accessToken: 'jwt',
    environment: 'sandbox',
    hidden: false
});

.create({accessToken: 'jwt', environment: 'sandbox', hidden: false})

Configuration of a new widget instance is made by calling .create() method. The options required are the following:

Create Parameters

Parameter Required Default Description
accessToken yes accessToken obtained server side (see more here)
environment yes "" 'sandbox' or 'production' are the permitted values.
hidden no false Create the widget in hidden mode (not visibile in the HTML).
screenSharingExtensionId no '' Extension ID of the Screen Sharing Extension. (see more here
screenSharingExtensionURL no '' The URL from witch download your custom extension (see more here
layout no {} Specify the custom layout (see more here)
record no false Specify if all the calls must be recorded.
recordingType no 'automatic' Allowed params are 'manual' or 'automatic', allows to define the recording type for all the calls
isAdmin no false Specify if the logged user is an admin, this capability allow to trigger the start/stop of the manual recording
callType no audio_video Specify the call type. Valid values are: "audio_only", "audio_upgradable", "audio_video"
mode no embed Specify the widget call mode. Valid values are: "embed" or "window"
language no it Specify the language of the widget. Valid values are: "it" or "en"
userDetailsProvider no default user provider Specify the information for each user (see more here)
userDetailsFormatter no default user formatter Specify how the user identity is formatted in the UI (see more here)
tools no All tools enabled Allows you to enable the available tools during the call and the chat for the widget (embed and window mode)(See more here)
virtualBackground no false Allowed params are 'blur' or 'image', allows to publish the local webcam with the blur or the replacement of the background as default (embed and window mode)
feedback no false Allowed to show a feedback view after the call

Deprecated parameters — Deprecation date: 26/11/20

Parameter Required Default Description
userAlias yes "" The widget who initialize the widget. Needs to create a user via rest API
appId yes "" A valid appId. Please contact Bandyer to have a valid appId
chat no true If false it disables the chat module so that the widget is only able to receive calls and create calls through the createCall API

Authentication

The authentication require the use of an accessToken obtained from your own server using the following api :

curl -X POST "https://sandbox.bandyer.com/rest/sdk/credentials" \
     -H "apikey: COMPANY_APIKEY" \
     -H "Content-Type: application/json" \
     -d '{
        {user_id: "user_xxx", expires_in: 360}
     }'

Example Response

{
    "access_token": "valid jwt for the user",
    "expires_at": "2022-01-10T11:41:19.000Z",
    "user_id": "user_xxx"
}

Return a valid accessToken to provide to the clients that needs a sdk authentication, please DO NOT request the token client side in order to not expose the api_key. If you expose the api_key the credential's generation for your company became unsafe.

HTTP Request

POST https://sandbox.bandyer.com/rest/sdk/credentials

Header Parameters

Parameter Required Default Description
apikey yes "" Every request must have the API Key.

Body Parameters

Parameter Required Default Description
user_id yes "" user that you want to authenticate
expires_in no 360 Seconds after that the token expires

Error

Status Name Code Reason
401 invalid_api_key invalid_api_key Apikey is not valid
422 validation_error invalid_token_expirations The expires_in must be between 360 (6 minutes) and 86400 (24 hours)

Once you have obtained the access token you are able to authenticate the sdk, in order to maintain the connected state you need to bind two events to the Client object(see Create):

  • access_token_is_about_to_expire
  • access_token_expired
client.on('access_token_is_about_to_expire', async (data) => { // data: {expiresAt: "2022-01-10T11:41:19.000Z"'}
    const accessToken = await yourAsyncFunction(); // async function that allow you to ask a new accessToken to the server
    // Provide the obtained accessToken to the sdk
    const { expiresAt } = await BandyerChat.updateAccessToken(accessToken); // return the new expiration date

})
client.on('access_token_expired', () => {
   // the session expired, for some reason the update token process is failed, you need to re-initilize the sdk
})

Call type options:

  • audio_only: the call is only audio and the participants can't use the webcam
  • audio_upgradable: the call begins with only audio but the participants can publish the webcam
  • audio_video: the call begins with audio and webcam

Mode options:

  • embed: the call is embedded in the widget view
  • window: the call is accessible in a window popup

Hidden options

The widget chat is not visible in the frontend until it receives the following events:

  1. addChat event
  2. incoming call event

Tools option

By default, if no tools are provided (missing field), all the tools are enabled. If the tools field is defined but empty, all the tools are disabled.

List of available tools

Name Mode Description
chat Window & Embed Enable the chat feature
screen_sharing Window & Embed Enable the screen_sharing feature
file_upload Window & Embed Enable the capability to send file
whiteboard Window If true enable all the whiteboard tools. Can be an object of whiteboard tools
snapshot Window Enable the snapshot feature
live_edit Window Enable the live_edit feature
live_pointer Window Enable to send pointer-events to others participants (always active in reception)

The whiteboard(WB), snapshot(SN) and live_edit(LE) tools are strictly correlated, so use it accordingly as follow:

Combination Receive live_edit Collaborate Snapshot & Gallery Open whiteboard
SN+ LE + WB
SN
SN + WB (default LE active in reception)
WB (default LE active in reception)
NONE

Whiteboard tools

{
    "tools": {
        "whiteboard": {
            "wb_add_file": true,
            "wb_cursor": true,
            "wb_text": true,
            "wb_shape": true,
            "wb_pen": true,
            "wb_eraser" : true
        }
    }
}

The whiteboard tools object is included in the tools parameter

Name Description
wb_add_file Allows to add files on the whiteboard
wb_cursor Allows to send the cursor events to the other participants
wb_text Allows to add text on the whiteboard
wb_shape Allows to add shape on the whiteboard
wb_pen Allows to using the pen on the whiteboard
wb_eraser Allows to erase a previous draw on the whiteboard
Returns:
Type

Promise.<(Client|Error)>

Custom layout

The widget has custom configurable layout to give the opportunity to match the look and feel you prefer. The layout option is composed by a list of other keys. The table above is the list of the available options:

Key Options Description
header background, color Specify the background and color of the header
headerButton background, color Specify the background and color of the header buttons
body background, color Specify the background and color of the body
launcher background Specify the background of the launcher
messageSent background, color Specify the background and color of the messages you sent
messageReceived background, color Specify the background and color messages you received
dial background, color Specify the background and color of the dial view
call background, color Specify the background and color of the call view
feedback body: {background, color}, buttons: {background, color} Specify the theme for the feedback view
fontFamily font Family Font family of the entire widget

Here an example:

BandyerChat.create({
    userAlias: 'usr_123456', 
    appId: 'wAppId_fake123456', 
    environment: 'sandbox', 
    layout: {
        body: {background: '#0069B4', color: '#000'}, 
        dial:{background: '#003762', color: '#fff'}, 
        call: {background: '#003762', color: '#fff'}, 
        messageSent: {background: '#003762', color: '#fff'}, 
        launcher: {background: '#0069B4'},
        header: {background: '#003762', color: '#fff'},
        headerButton: {background: '#0069B4', color: '#fff'}, 
        feedback: {body: {background: '#0069B4', color: '#fff'}, buttons: {background: '#0069B4', color: '#fff'}},
        fontFamily: '"Segoe UI","Segoe",Tahoma,Helvetica,Arial,sans-serif' 
    }
})

userDetailsProvider

The widget has a custom configurable function that allows customizing the users' information, which later will be displayed in the UI.

The userDetailsProvider is optional, but if defined must be a function.

This function takes an array of String (userAlias) as the only input parameter and must return a Promise that contains an Array of objects, one object for each userAlias provided as input.

Performance considerations The userDetailsProvider function is called and waited internally for up to 1200 ms, otherwise it default to the default provider logic. For this reason your logic will be applied only if it is faster then 1200 ms.

Every single object representing a user and must contain a userAlias key(otherwise the object will be ignored) and optionally other keys that can be used to define the logic used in your custom userDetailFormatter.

Here an example:


yourProviderFunction = function (usersAlias){
    const userObjPromises = [];
    usersAlias.forEach( (alias) => {
        // Your logic here
        const user = yourAsyncFetchFunction(alias);
        // Example of yourAsyncFetchFunction promise return
        /*{
            userAlias: alias,
            firstName: myFirstName,
            lastName: myLastName,
            image: myImage
        };*/
        usersObjPromises.push(user);
    });
    return Promise.all(userObjPromises);
}

BandyerChat.create({
    userAlias: 'usr_123456',
    appId: 'wAppId_fake123456',
    environment: 'sandbox',
    userDetailsProvider: yourProviderFunction
})

N.B define a userDetailsProvider without the relative userDetailsFormatter is useless since the displayed result will be the userAlias as it is the default logic of userDetailsFormatter.

userDetailsFormatter

The widget has a custom configurable function that lets you customize how users name are displayed in the UI. The userDetailsFormatter is optional, but if defined, it must be a function.

This function takes as input parameter an Object that represents one user and must return a String that represents how the user identity must be displayed in the UI.

If the return value is not a String or the logic fails, the displayed information will be the userAlias.

Here an example:


yourFormatterFunction = function (user){
    return user.firstName + " " + user.lastName;
}

BandyerChat.create({
    userAlias: 'usr_123456',
    appId: 'wAppId_fake123456',
    environment: 'sandbox',
    userDetailsFormatter: yourFormatterFunction
})

N.B define a userDetailsFormatter without the relative userDetailsProvider can be useless since the displayed result will use the information provided at user creation.

logout

.logout()

BandyerChat.logout();

To logout to the current istance of the widget, you can call the .logout() method. The logout() method will unmount the widget component.

Returns:
Type

Promise.<(void|Error)>

version

.version()

BandyerChat.version();

Return the current version of the widget

Returns:
Type

String

Client

A Client is a starting point to access Bandyer Chat functionality. It is possible to listen events which are fired by the widget. A Client is returned by the create method.

const Client = BandyerChat.create({
    userAlias: 'usr_123456', 
    appId: 'wAppId_fake123456', 
    environment: 'sandbox',
    hidden: false,
    screenSharingExtensionId: 'id of your screen sharing extension'
});

Add chat

.addChat(userAlias)

BandyerChat.addChat('usr_fr55ga3');

.addChat('usr_fr55ga3')

To enable the chat with another user of your platform, you need to call the .addChat() method. The addChat method expect a valid user alias (it must be a user already created). Once the method is called, the widget will display the chat added.

Note: if the widget is in hidden mode, the addChat method mode will display the widget. Note: if the widget is initialized with chat: false this method returns an error: 'Chat module not initialized'

Arguments:
Name Type Description
userAlias String User whose chat is to be added
Returns:
Type

Promise.<(void|Error)>

Remove chat

.removeChat(userAlias)

BandyerChat.removeChat('usr_fr55ga3');

.removeChat('usr_fr55ga3')

To remove a chat you need to call the .removeChat() method. The removeChat will remove the chat between the user authenticated and the user specified as input of the method. All the messages between them will be deleted permanently.

Note: if the widget is initialized with chat: false this method returns an error: 'Chat module not initialized'

Arguments:
Name Type Description
userAlias String User whose chat is to be removed
Returns:
Type

Promise.<(void|Error)>

isAuthenticated

.isAuthenticated()

BandyerChat.isAuthenticated();

.isAuthenticated()

To check if the current istance of the widget is authenticated, you need to call the .isAuthenticated() method. The method will return true if the widget is authenticated, false otherwise.

Returns:
Type

Type: boolean

Select chat

.selectChat(userAlias)

BandyerChat.selectChat('usr_fr55ga3');

.selectChat('usr_fr55ga3')

To select a chat you need to call the .selectChat() method. The selectChat will select the chat between the user authenticated and the user specified as input of the method.

Note: if the widget is initialized with chat: false this method returns an error: 'Chat module not initialized'

Arguments:
Name Type Description
userAlias String User whose chat is to be selected
Returns:
Type

Promise.<(void|Error)>

createCall

.createCall(Array, options)

BandyerChat.createCall(['usr_fr55ga3'], {'call_type':'audio_video'});

Create a call with arbitrary call options with the users specified in the array (Only one user)

Note: If the widget is in hidden mode, the createCall method mode will display the widget.

Arguments:
Name Type Description
usersAlias Array of String List of users with whom you want to start a call
options Object Call options
Options
Name Default Type Description
callType inherit from the config string Can be 'audio_only', 'audio_upgradable', 'audio_video'
record or recording inherit from the config boolean Allow to define if the call start with recording
recordingType inherit from the config string Can be 'manual' or 'automatic'
isAdmin inherit from the config boolean Allow the user to control the manual recording capabilities

N.B. if the call is {recording: true, recordingType: 'manual', isAdmin: false} create a call with the recording capability but no-one is able to start the recording. In order to do that create this type of call with isAdmin: true

Returns:
Type

Promise.<(Call|Error)>

Key Type Description
callAlias String Unique alias of the current call
callDirection String Direction of the call (incoming
callParticipants Array Array of userAlias of the participants
callStatus String Status of the call, can be dialing, connected, ended
hangUp Function Allow to hangUp the call
callOptions Object Basic information about the call
CallOptions:
Key Type Description
record Boolean True if the call has been initialized with recording
creationDate Date Date and time of the created call
callType String audio_only, audio_upgradable, audio_video
live Boolean This param defines whether the link should trigger widget and mobile ringing or not.
Error:
Key Type Description
ANOTHER_CALL_IN_PROGRESS String There are another active call
INITIATOR_NOT_AVAILABLE String The caller is not available
USERS_BUSY_ERROR String The called user is busy
INVALID_PERMISSION_CAN_VIDEO" String The user does not have permissions for a video call
HANG_UP_ON_ENDED_CALL String When try to call hangUp on an ended call
GENERIC_CALL_ERROR String Something went wrong, please retry

joinCallURL

.joinCallURL(url)

BandyerChat.joinCallURL('https://sandbox.bandyer.com/connect/rest-call-handler/mycustomtoken');

Join a one to one call from an URL.

The widget must be authenticated and the url must be coupled with the user authenticated on the widget.

Join call URLs can be created using the dedicated /rest/room/create API . Documentation can be found here

Note: If the widget is in hidden mode, the joinCallURL method mode will display the widget.

Arguments:
Name Type Description
url String Rest link to the call
Returns:
Type

Promise.<(Call|Error)>

Key Type Description
callAlias String Unique alias of the current call
callDirection String Direction of the call (incoming
callParticipants Array Array of userAlias of the participants
callStatus String Status of the call, can be dialing, connected, ended
hangUp Function Allow to hangUp the call
callOptions Object Basic information about the call
CallOptions:
Key Type Description
record Boolean True if the call has been initialized with recording
creationDate Date Date and time of the created call
callType String audio_only, audio_upgradable, audio_video
live Boolean This param defines whether the link should trigger widget and mobile ringing or not.
Error:
Key Type Description
ANOTHER_CALL_IN_PROGRESS String There are another active call
JOIN_CALL_REQUEST_FAILED String The user is busy or there is a network error
JOIN_CALL_INVALID_URL String The given url is not correct
JOIN_CALL_INVALID_MTM String Impossible to start a many to many call
HANG_UP_ON_ENDED_CALL String When try to call hangUp on an ended call
GENERIC_CALL_ERROR String Something went wrong, please retry

composeMessage

.composeMessage(userAlias, message, send)

BandyerChat.composeMessage('usr_fr55ga3', 'How are you?', true);

Compose and optionally send a message to a user.

If send === true the specified message is sent directly to the specified user chat without trigger UI changes. Otherwise ( send === false), the widget will display the chat and fill the input text with the specified message, letting the user decide wether edit it before send it.

Note: If the widget is in hidden mode, the message is sent anyway. Note: if the widget is initialized with chat: false this method returns an error: 'Chat module not initialized'

Arguments:
Name Type Description
userAlias String User to whom compose o send message
message String Text of the message
send boolean If true, directly send the message otherwise inflate the message in the UI
Returns:
Type

Promise.<(void|Error)>

Events

Event Description
typing_started Fired when a User has started typing
message_sent Fired when a User has sent a message
message_received Fired when a User has received a message
message_read Fired when a User has read a message
chat_loaded Fired when Chat channel is loaded
user_connected Fired when a User connects to the platform
user_disconnected Fired when a User disconnects to the platform
incoming_call Fired when a User create or receive a call
call_dial_answered Emitted when a user answers a dial
call_dial_declined Emitted when a user declines a dial
call_dial_stopped Emitted when a user stop a dial
call_started Fired when a call start
call_ended Fired when a call end
force_disconnect Fired when the server close the connection due to a user disable or delete

Typing started

Client.on('typing_started',(data) => {
    // your logic
});

Fired when a User has started typing.

Note: To optimise network traffic, Client endpoints will only send a Typing signal once every 5 seconds

Type
Key Type Description
userAlias String Alias of the user
chat String Unique identifier of the chat
participants Array Array of participants

Message sent

Client.on('message_sent',(data) => {
    // your logic
});

Fired when a User has sent a message.

Type
Key Type Description
id String Unique identifier of the message
chat String Unique identifier of the chat
participants Array Array of participants
text String Text of the message
timestamp Date When message was created
sender String User alias of the creator of the message

Message received

Client.on('message_received',(data) => {
    // your logic
});

Fired when a User has received a message.

Type
Key Type Description
id String Unique identifier of the message
chat String Unique identifier of the chat
participants Array Array of participants
text String Text of the message
timestamp Date When message was created
sender String User alias of the creator of the message

Message read

Client.on('message_read',(data) => {
    // your logic
});

Fired when a User has read a message.

Type
Key Type Description
id String Unique identifier of the message
chat String Unique identifier of the chat
participants Array Array of participants
text String Text of the message
timestamp Date When message was created
sender String User alias of the creator of the message

Chat loaded

Client.on('chat_loaded',(data) => {
    // your logic
});

Fired when the chat channel is loaded

Type
Key Type Description
chat String Unique identifier of the chat
participants Array Array of participants
lastMessage.author String Author of the message
lastMessage.message String Text of the message
lastMessage.timestamp String Timestamp of the message
dateCreated Date When channel was created
createdBy String Creator of the channel
unreadMessages Number Number of unread messages

User connection

Client.on('user_connected',(data) => {
    // your logic
});

Fired when a user connects one platform

Type
Key Type Description
userAlias String User alias of the user
status String Current status ('online', 'offline')

User disconnection

Client.on('user_disconnected',(data) => {
    // your logic
});

Fired when a user disconnects all the platforms

Type
Key Type Description
userAlias String User alias of the user
status String Current status ('online', 'offline')

Dial Events

The dial events let you know when one of the two users takes an action that will bring the call into a new state

Incoming call

Client.on('incoming_call',(call) => {
    // your logic
});

Fired when a User create or receive a call.

To discriminate whether the call has been created or received, it is necessary to refer to the callDirection, outgoing in case of creation, incoming in case of reception

call object:

The data in the event is a call object:

{
  "event": "incoming_call",
  "callAlias": "room_027b9312e9a5",
  "callDirection": "outgoing",
  "callParticipants": ["user1", "user2"],
  "callOptions": {
    "record": false,
    "creationDate": "2021-04-13T08:31:03.916Z",
    "callType": "audio_video", 
    "live": true
  }
}
Key Type Description
event String Event name
callAlias String Unique alias of the current call
callDirection String Direction of the call (incoming/outgoing)
callParticipants Array Array of userAlias of the participants
callOptions Object Basic information about the call
CallOptions:
Key Type Description
record Boolean True if the call has been initialized with recording
creationDate Date Date and time of the created call
callType String audio_only, audio_upgradable, audio_video
live Boolean This param defines whether the link should trigger widget and mobile ringing or not.

Dial Answered

Client.on('call_dial_answered',(call) => {
    // your logic
});

Fired when the user(executor) answered on a dial event.

This event is raised for both users. The 'executor' field allows you to understand which user performed the action

call object:

The data in the event is a call object:

{
  "event": "call_dial_answered",
  "executor": "user2",
  "callAlias": "room_027b9312e9a5",
  "callDirection": "outgoing",
  "callParticipants": ["user1", "user2"],
  "callOptions": {
    "record": false,
    "creationDate": "2021-04-13T08:31:03.916Z",
    "callType": "audio_video",
    "live": true
  }
}
Key Type Description
event String Event name
callAlias String Unique alias of the current call
executor String UserAlias of the participant that have performed the action
callDirection String Direction of the call (incoming/outgoing)
callParticipants Array Array of userAlias of the participants
callOptions Object Basic information about the call
CallOptions:
Key Type Description
record Boolean True if the call has been initialized with recording
creationDate Date Date and time of the created call
callType String audio_only, audio_upgradable, audio_video
live Boolean This param defines whether the link should trigger widget and mobile ringing or not.

Dial Declined

Client.on('call_dial_declined',(call) => {
    // your logic
});

Fired when a user declines a call.

This event is raised for both users. The 'executor' field allows you to understand which user performed the action

call object:

The data in the event is a call object:

{
  "event": "call_dial_declined",
  "executor": "user2",
  "callAlias": "room_027b9312e9a5",
  "callDirection": "outgoing",
  "callParticipants": ["user1", "user2"],
  "callOptions": {
    "record": false,
    "creationDate": "2021-04-13T08:31:03.916Z",
    "callType": "audio_video",
    "live": true
  }
}
Key Type Description
event String Event name
callAlias String Unique alias of the current call
executor String UserAlias of the participant that have performed the action
callDirection String Direction of the call (incoming\outgoing)
callParticipants Array Array of userAlias of the participants
callOptions Object Basic information about the call
reason String Valid reasons are: none, do_not_disturb, no_answer, error or answered_another_call
CallOptions:
Key Type Description
record Boolean True if the call has been initialized with recording
creationDate Date Date and time of the created call
callType String audio_only, audio_upgradable, audio_video
live Boolean This param defines whether the link should trigger widget and mobile ringing or not.

Dial stopped

Client.on('call_dial_stopped',(call) => {
    // your logic
});

Fired when a call ends.

This event is raised for both users. The 'executor' field allows you to understand which user performed the action

call object:

The data in the event is a call object:

{
  "event": "call_dial_stopped",
  "executor": "user2",
  "callAlias": "room_027b9312e9a5",
  "callDirection": "outgoing",
  "callParticipants": ["user1", "user2"],
  "callOptions": {
    "record": false,
    "creationDate": "2021-04-13T08:31:03.916Z",
    "callType": "audio_video",
    "live": true
  }
}
Key Type Description
event String Event name
callAlias String Unique alias of the current call
executor String UserAlias of the participant that have performed the action
callDirection String Direction of the call (incoming\outgoing)
callParticipants Array Array of userAlias of the participants
callOptions Object Basic information about the call
CallOptions:
Key Type Description
record Boolean True if the call has been initialized with recording
creationDate Date Date and time of the created call
callType String audio_only, audio_upgradable, audio_video
live Boolean This param defines whether the link should trigger widget and mobile ringing or not.

Call events

Call started

Client.on('call_started',(call) => {
    // your logic
});

Fired when the call start, this event is raised only after a call_dial_answered event.

This event is raised for both the users but don't have an executor because is a general event that represents when both the users are in call.

call object:

The data in the event is a call object:

{
  "event": "call_started",
  "callAlias": "room_027b9312e9a5",
  "callDirection": "outgoing",
  "callParticipants": ["user1", "user2"],
  "callOptions": {
    "record": false,
    "creationDate": "2021-04-13T08:31:03.916Z",
    "callType": "audio_video",
    "live": true
  }
}
Key Type Description
event String Event name
callAlias String Unique alias of the current call
callDirection String Direction of the call (incoming/outgoing)
callParticipants Array Array of userAlias of the participants
callOptions Object Basic information about the call
CallOptions:
Key Type Description
record Boolean True if the call has been initialized with recording
creationDate Date Date and time of the created call
callType String audio_only, audio_upgradable, audio_video
live Boolean This param defines whether the link should trigger widget and mobile ringing or not.

Call ended

Client.on('call_ended',(call) => {
    // your logic
});

Fired when the call ends.

This event is raised for both users. The 'executor' field allows you to understand which user performed the action

call object:

The data in the event is a call object:

{
  "event": "call_ended",
  "executor": "user2",
  "callAlias": "room_027b9312e9a5",
  "callDirection": "outgoing",
  "callParticipants": ["user1", "user2"],
  "callOptions": {
    "record": false,
    "creationDate": "2021-04-13T08:31:03.916Z",
    "callType": "audio_video",
    "live": true
  }
}
Key Type Description
event String Event name
callAlias String Unique alias of the current call
executor String UserAlias of the participant that have performed the action
callDirection String Direction of the call (incoming\outgoing)
callParticipants Array Array of userAlias of the participants
callOptions Object Basic information about the call
CallOptions:
Key Type Description
record Boolean True if the call has been initialized with recording
creationDate Date Date and time of the created call
callType String audio_only, audio_upgradable, audio_video
live Boolean This param defines whether the link should trigger widget and mobile ringing or not.

Force disconnect

Client.on('force_disconnect',(data) => {
    // your logic
});

Fired when a server close the connection due to a user disable or delete. The data in the event is an object:

Key Type Description
reason String Can be user_deleted or user_disabled, specify the reason of the force disconnect

Widget Operations

Operation Description
Show widget Show the widget in the html page
Hide widget Hide the widget in the html page
Toggle widget Toggles the widget from open to close view or viceversa
Open widget Opens the widget
Close widget Closes the widget

Show widget

.showWidget()

BandyerChat.showWidget();

Show the widget in the html page.

Returns:
Type

Type: Boolean.(true|false)>

Hide widget

.hideWidget()

BandyerChat.hideWidget();

Hide the widget in the html page.

Returns:
Type

Type: Boolean.(true|false)>

toggleWidget

.toggleWidget()

BandyerChat.toggleWidget();

Toggles the widget from open to close view or viceversa.

Returns:
Type

Type: Boolean.<(true|false)>

openWidget

.openWidget()

BandyerChat.openWidget();

Opens the widget.

Returns:
Type

Type: Boolean.<(true|false)>

closeWidget

.closeWidget()

BandyerChat.closeWidget();

Closes the widget.

Returns:
Type

Type: Boolean.<(true|false)>

 Activities

To build custom business logic based on Widget activities (message sent, received, etc), the widget gives useful methods. Here a list of them:

Method Description
getUser Get the user info and his current status (online, offline, busy)
getLastMessageReceived Get the last message received by the user
getLastMessageSent Get the last message sent by the user
getUnreadMessages Get all the unread messages of the user

getUser

.getUser(userAlias)

BandyerChat.getUser(userAlias);

Get User status

Arguments:
Name Type Description
userAlias String User of whom you want to find information
Returns:
Type {userAlias, status}
Key Type Description
userAlias String Unique identifier of the user
status String Status of the user can be online, busy or offline

getUsersStatusList

.getUsersStatusList()

BandyerChat.getUsersStatusList();

Get the list of the connected users

Returns:
Type Array<[User]>

Array of object:

Key Type Description
userAlias String Unique identifier of the user
status String Status of the user can be online, busy

getChats()

. getChats()

BandyerChat.getChats();

Get all the chat of the client.

Returns:
Type

Array of object:

Key Type Description
chat String Unique identifier of the chat
unreadMessages Number Number of unread messages
participants Array Array of participants
lastMessage.author String User alias of the autor of the last message
lastMessage.message String Text of the last message
lastMessage.timestamp Date Timestamp of the last message

getLastMessageReceived

.getLastMessageReceived()

BandyerChat.getLastMessageReceived();

Get the last message received by the widget in the current session.

Returns:
Type
Key Type Description
id String Unique identifier of the message
chat String Unique identifier of the chat
participants Array Array of participants
text String Text of the message
timestamp Date When message was created
sender String User alias of the creator of the message

getLastMessageSent

.getLastMessageSent()

BandyerChat.getLastMessageSent();

Get the last message sent by the widget in the current session.

Returns:
Type
Key Type Description
id String Unique identifier of the message
chat String Unique identifier of the chat
participants Array Array of participants
text String Text of the message
timestamp Date When message was created
sender String User alias of the creator of the message

getUnreadMessages

.getUnreadMessages()

BandyerChat.getUnreadMessages();

Get the unread messages of the user.

Returns:
Type

Array of object:

Key Type Description
chat String Unique identifier of the chat
unreadMessages Number Number of unread messages

Screen sharing

From version 1.1.0 the widget allows to publish a screen as the video source. A client connected to the widget can subscribe to the stream (and view it), just as they would subscribe to a stream that uses a camera as the source.

In Chrome with a version lower than 72, to publish a screen-sharing video, the client needs to add an extension that enables publishing screen-sharing streams for your domain. As of Firefox 52, an extension (or whitelist listing) is no longer needed for screen sharing. Firefox prompts the end user for access to a screen, window, or application, as it would for access to the camera.

In all browsers, publishing a screen-sharing stream requires the page to be loaded over HTTPS.

Set url for extension install

The BandyerChat.create() parameter screenSharingExtensionURL or the function BandyerChat.setExtensionUrl('URL_CHROME_WEBSTORE') is used to specify the URL where to download the screensharing extension from the chrome web store. It's important to set the url to allow the user to add a custom extension. (How to build a custom extension)

BandyerChat.create({
    userAlias: 'usr_123456',
    appId: 'wAppId_fake123456',
    environment: 'sandbox',
    screenSharingExtensionURL: 'https://chrome.google.com/webstore/detail/your-extension/your-extension-id'
})

or

BandyerChat.setExtensionUrl('https://chrome.google.com/webstore/detail/your-extension/your-extension-id')

If the user requires to share the screen and hasn't installed the extension yet, the widget will display this alert:

Drawing

Build a customized screensharing chrome extension

To support screen-sharing in Chrome older than v72, a Chrome screen-sharing extension must be created. Notice that the extension must be built to work in your own domain. A template extension to use as the base to build your own custom extension can be found in the extra folder. Download and unzip the ScreenShareExtension.zip file and follow this guidelines:

Modify manifest.json file

First of all open the manifest.json file, it look like this

{
   "author": "Bandyer srl",
   "background": {
      "persistent": true,
      "scripts": [ "background-script.js" ]
   },
   "description": "Extension to allow screen sharing in Bandyer playground application.",
   "homepage_url": "https://playground.bandyer.com",
   "icons": {
      "128": "icon.png"
   },
   "externally_connectable": {
      "matches": ["*://localhost/*", "*://*.bandyer.com/*"]
   },
   "manifest_version": 2,
   "minimum_chrome_version": "34",
   "name": "Bandyer Playground Screensharing",
   "permissions": [ "desktopCapture"],
   "update_url": "https://clients2.google.com/service/update2/crx",
   "version": "1.0.0",
   "web_accessible_resources": [ "icon.png" ]
}

Edit the following parameter:

  • author: Insert your author parameter
  • description: Briefly explain what the extension does
  • homepage_url: Link to your home page
  • matches: This field is the most important. List here all the domains that should have permission to access to that extension, note that the '*' character.

Further explaination

   {
  "background": {
    "persistent": true,
    "scripts": [
      "background-script.js"
    ]
  }
}

In this section there are two parameters:

  • persistent: set to true, it allows the extension to keep staying active even if the user is not interacting with the page.
  • scripts: specify the script name that will be executed.
Load a new icon

Substitute the icon in the directory of the extension that you have downloaded with your own. Notice that chrome require an icon for every extension. Be aware of the fact that the icon name must be exactly icon.png (This because the system uses the icon name as input to check if the extension is properly installed on the client)

Install an unpacked/unpublished extension into chrome browser (for development purposes)
  • Navigate to chrome://extensions in your browser. You can also access this page by clicking on the Chrome menu on the top right side of the Omnibox, hovering over More Tools and selecting Extensions.
  • Check the box next to Developer Mode.
  • Click Load Unpacked Extension and select the directory for your "Custom Extension" extension.

Please take note of the extension id and remember that this id changes every time the unpacked extension is installed on a client. Once the extension has been published to the chrome web store the id will remain the same for each installation.

  • Insert the extension id during the widget creation phase
BandyerChat.create({
    userAlias: 'usr_123456',
    appId: 'wAppId_fake123456',
    environment: 'sandbox',
    screenSharingExtensionId: 'Your extension id'
})

Distributing a screen-sharing extension

In order to enable screen-sharing on your website, users with a Chrome version lower than 72, need to install your custom screen-sharing extension. Once completed the previous steps, the extension is ready to be published on the chrome web store. Pack (zip) the Chrome extension folder and publish it in the Chrome Web Store

Before continue, remember to remove unwanted hosts from the manifest

  • Decide which Google Account is your developer account—the account that you'll use to verify ownership and publish your app. Instead of using your personal Gmail account, you might want to create a dedicated account for your apps. For details, see Choose a developer account in Publishing Your App. Note: If you created a blog, choose the account that you used to create that blog.

  • Go to the Chrome Developer Dashboard, and sign into your developer account. Once you sign in, you'll see a list of any installable web apps, extensions, and themes that you've already uploaded.

  • Click the Add new item button in the dashboard. If you've never uploaded an installable web app, extension, or theme before, you need to accept the developer agreement before going on.

  • Click Choose file, choose the ZIP file you created in Step 5, and click Upload. If you see an error message, fix the error, zip up the directory again, and upload the ZIP file.

Within seconds you should see the Edit page for your app. At the top, you might see a warning that you must verify ownership for whatever sites you specified in the "urls" and "web_url" fields. That warning has a link that takes you to Google Webmaster Tools, where you can verify ownership at any time before you publish the app.

After a successfull publication, your extension will have a unique id, that can be used as parameter in the BandyerChat.create() function to use it in yuor own integration.

For further info visit Chrome Developer tutorial