JavaScript SDK for customer-facing channels

This guide targets web third-party clients building a custom customer-facing widget with @expertflow/sdk-for-customer-facing-channels v6.2.0 (published NPM). Native / React Native usage is out of scope for this page.

This SDK embeds Expertflow CX chat and WebRTC calling in your own web UI. You own the presentation layer; the SDK handles channel session, messaging, files, and media signalling.

SDK Capabilities

With this SDK, the developer can enable the customer to:

  • Start and end chat

  • Send and receive chat messages (including rich media) and delivery notifications

  • Make audio / video / screen-share calls via WebRTC and control mute, hold, and stream conversion

  • Receive system socket events for session lifecycle and reconnect

  • Load widget settings and pre-chat forms from Unified Admin

  • Optional: callback request, webhook notification, secure-link authentication, business calendar lookup

  • Contact center stats, agent availability, and expected waiting time — ROADMAP

Prerequisites

  1. Access to Expertflow CX Unified Admin to create a Customer Widget and channel settings.

  2. Deployed CX endpoints: CCM, Web Channel Manager (socket), File Engine, Unified Admin forms, and (for calls) EF Switch WebRTC.

  3. A modern browser with microphone/camera permissions for WebRTC.

Install (Web)

Option A — NPM (recommended for bundled web apps)

Bash
npm i @expertflow/sdk-for-customer-facing-channels@6.2.0
JavaScript
import * as customerSDK from '@expertflow/sdk-for-customer-facing-channels';
// or
const customerSDK = require('@expertflow/sdk-for-customer-facing-channels');

The package depends on socket.io-client and ships SIP.js (dist/sip-0.21.2.min.js). Ensure your bundler can resolve these assets and that the browser environment provides window / MediaStream for WebRTC.

Option B — CDN / static assets

For script-tag apps, pin a release instead of @latest:

HTML
<script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/expertflow/sdk-for-customer-facing-channels@6.2.0/dist/sip-0.21.2.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/expertflow/sdk-for-customer-facing-channels@6.2.0/dist/index.js"></script>

Load order: Socket.IO → SIP.js → SDK.

Package reference: npm · GitHub

Configuration

Client configuration (your app)

Pass these URLs/identifiers from your app config into SDK calls (they are not magically read from a global config.js).

Property

Explanation

Sample

widgetIdentifier

Widget key in CCM

Web

serviceIdentifier

Channel / DN used by channel manager

5155

socketUrl

Web Channel Manager base URL

https://<fqdn>/web-channel-manager

ccmUrl

Customer Channel Manager base URL

https://<fqdn>/ccm

fileServerUrl

File Engine base URL

https://<fqdn>/file-engine

formUrl

Unified Admin base URL (forms APIs)

https://<fqdn>/unified-admin

authenticatorUrl

Secure-link verifier (optional)

https://<fqdn>/secure-link

businessCalendarUrl

Business calendar API (optional)

https://<fqdn>/business-calendar

channelIdentifier

Pre-chat field used as customer id

phone

Widget + WebRTC settings (Unified Admin)

Configure the widget in Unified Admin. WebRTC fields used by the SDK login path:

Property

Explanation

Sample

wssFs

Full WSS URL of EF Switch

wss://192.168.0.101:7443

uriFs

SIP domain / FS host used in SIP URI

192.168.0.101

diallingUri

DN to dial

369852

sipExtension

SIP extension for registration

1001

extensionPassword

SIP password

********

enabledSipLogs

Enable SIP debug logs

true

iceServers

STUN/TURN list

[{\"urls\":[\"stun:stun.l.google.com:19302\"]}]

form

Pre-chat form id

67e639de…

Older docs used wssServerIp / wssServerPort. Current SDK login path expects wssFs and uriFs.

Quick start — chat flow

  1. widgetConfigs(ccmUrl, widgetIdentifier, cb) — load theme, form id, WebRTC flags.

  2. Optional: formValidation(formUrl, cb) then getPreChatForm(formUrl, formId, cb).

  3. establishConnection(socketUrl, serviceIdentifier, channelCustomerIdentifier, cb).

  4. On SOCKET_CONNECTED: call chatRequest({ type: 'CHAT_REQUESTED', data: customerData }) for a new chat, or resumeChat({ serviceIdentifier, channelCustomerIdentifier }, cb) if a session already exists.

  5. On CHANNEL_SESSION_STARTED: store conversationId; optionally setConversationDataByCustomerIdentifier(...).

  6. Exchange messages with sendChatMessage(cimPayload).

  7. End with chatEnd(customerData).

Customer data payload

JavaScript
{
  serviceIdentifier: "5155",
  channelCustomerIdentifier: "923001234567",
  browserDeviceInfo: {
    browserId: "123124",
    browserIdExpiryTime: "9999",
    browserName: "chrome",
    deviceType: "desktop"
  },
  queue: "",
  locale: {
    timezone: "asia/karachi",
    language: "english",
    country: "pakistan"
  },
  formData: {
    attributes: [
      { key: "firstName", value: "Jane", type: "string" }
    ],
    createdOn: "2026-08-11T06:00:00.000Z",
    filledBy: "web-init",
    formId: "0.0313465461351",
    id: "0.1025556665461"
  }
}

Chat API reference

Function

Parameters

Notes

widgetConfigs(ccmUrl, widgetIdentifier, callback)

CCM URL, widget id, callback

GET {ccmUrl}/widget-configs/{widgetIdentifier}

establishConnection(socketUrl, serviceIdentifier, channelCustomerIdentifier, callback)

4 args — socket URL is required first

Creates Socket.IO connection with auth payload; wires event listeners

chatRequest(data)

{ type, data: customerData }

Emits socket event CHAT_REQUESTED (not CHAT_REQUEST)

resumeChat({ serviceIdentifier, channelCustomerIdentifier }, callback)

Identifiers + callback

Emits CHAT_RESUMED; callback receives { isChatAvailable, … }

sendChatMessage(data)

CIM message envelope

Use this for chat. Emits MESSAGE_RECEIVED on the socket

chatEnd(data)

Customer identifiers payload

Emits CHAT_ENDED and disconnects

uploadToFileEngine(fileServerUrl, formData, callback)

File Engine URL + FormData

POST {fileServerUrl}/api/uploadFileStream

getPreChatForm(formUrl, formId, callback)

Unified Admin URL + form id

GET {formUrl}/forms/{formId}

formValidation(formUrl, callback)

Unified Admin URL

GET {formUrl}/formValidation

setConversationData(url, conversationId, data)

Conversation manager URL

By conversation id

getConversationData(url, conversationId)

Conversation manager URL

By conversation id

setConversationDataByCustomerIdentifier(url, channelIdentifier, data, callback)

URL + customer id

Preferred path used by Expertflow Customer Widget

getConversationDataByCustomerIdentifier(url, channelIdentifier, callback)

URL + customer id

Fetch stored conversation data

voiceRequest(data)

Same shape as chat customer data

Emits VOICE_REQUESTED

callbackRequest(url, payload, callback)

ECM callback URL + campaign payload

Optional callback feature

webhookNotifications(webhookUrl, additionalData, data)

Webhook URL + form map

Posts a card-style notification payload

authenticateRequest(authenticatorUrl, authData, callback)

Secure-link URL + { roomId }

POST /verifySecureLink

getBrowserInfo(apiKey, callback)

ipdata.co API key

Optional geo/browser enrichment

getCalendarId(ccmUrl, serviceIdentifier, callback)

CCM URL + service id

Resolves business calendar id

getCalendarEvents(calendarId, calendarUrl, startTime, endTime, callback)

Calendar URL + ISO range

Contact-center available timings helper

Do not confuse sendChatMessage (chat CIM over Socket.IO) with sendMessage(message, dialogId) (SIP MESSAGE during an active WebRTC call).

Messaging (CIM)

Full message schema: CIM Messages.

Minimal outbound text example:

JavaScript
customerSDK.sendChatMessage({
  type: "CUSTOMER",
  header: {
    sender: { id: "<customer-uuid>", type: "CUSTOMER", senderName: "Jane" }
  },
  body: {
    type: "PLAIN",
    markdownText: "Hello"
  },
  customer: customerData
});

Common body.type values: PLAIN, FILE, IMAGE, VIDEO, AUDIO, FORM_DATA. Delivery receipts use type DELIVERYNOTIFICATION.

Chat resume

  1. Persist serviceIdentifier and channelCustomerIdentifier (and ideally conversationId) in local/session storage.

  2. On page load, call establishConnection(socketUrl, serviceIdentifier, channelCustomerIdentifier, cb).

  3. If callback type is SOCKET_CONNECTED or SOCKET_RECONNECTED, call resumeChat({ serviceIdentifier, channelCustomerIdentifier }, cb).

  4. If resume reports chat available, render history from the resume response / subsequent MESSAGE_RECEIVED events.

SOCKET_RECONNECTED is emitted when Socket.IO connects after a prior CONNECT_ERROR that set localStorage.widget-error.

Socket events

All of the following are delivered through the callback passed to establishConnection as { type, data }.

type

When

Client action

SOCKET_CONNECTED

Socket.IO connect

Start chat (chatRequest) or resume

SOCKET_RECONNECTED

Connect after stored widget-error

Call resumeChat

CONNECT_ERROR

Socket.IO connect failure

Retry / show offline UI

SOCKET_DISCONNECTED

Socket.IO disconnect

Disable composer; reconnect strategy

CHANNEL_SESSION_STARTED

New channel session

Store conversationId; push form/conversation data

MESSAGE_RECEIVED

Inbound CIM message

Render message; send delivery notification if needed

CHAT_ENDED

Chat closed

Clear session UI (socket also disconnects)

ERRORS

Server error payload

Surface error to user

Some deployments / widget builds also surface CHANNEL_SESSION_ENDED, CHANNEL_SESSION_EXPIRED, SESSION_REPLACED, CONVERSATION_RESUMED, and TOKEN_GENERATED. Handle them if your CX version emits them; treat them as additive to the NPM 6.2.0 baseline above.

For web widgets, use the centralized postMessages({ action, parameter }) API (this is what Expertflow’s Customer Widget uses). Pass a clientCallbackFunction to receive events.

Actions

action

Purpose

Key parameter fields

login

Register SIP user agent

extension, sipConfig (wssFs, uriFs, extensionPassword, enabledSipLogs), clientCallbackFunction

makeCall

Start outbound audio/video call

callType (audio or video), calledNumber, Destination_Number, authData, clientCallbackFunction

mute_call / unmute_call

Toggle microphone

dialogId, clientCallbackFunction

holdCall / retrieveCall

Hold / resume

dialogId, clientCallbackFunction

convertCall

Toggle video or screenshare

dialogId, streamType (video or screenshare), streamStatus (on or off), clientCallbackFunction

SendDtmf

Send DTMF

message, dialogId, clientCallbackFunction

releaseCall

End active call

dialogId

logout

Unregister SIP session

clientCallbackFunction

answerCall

Answer inbound (if applicable)

dialogId, answerCalltype, clientCallbackFunction

Sample — login and dial

JavaScript
customerSDK.postMessages({
  action: "login",
  parameter: {
    loginId: webRtc.sipExtension,
    password: webRtc.extensionPassword,
    extension: webRtc.sipExtension,
    sipConfig: webRtc, // must include wssFs, uriFs, extensionPassword, enabledSipLogs
    clientCallbackFunction: onWebRtcEvent
  }
});

customerSDK.postMessages({
  action: "makeCall",
  parameter: {
    callType: "audio", // or "video"
    Destination_Number: webRtc.diallingUri,
    calledNumber: webRtc.diallingUri,
    authData: webRtc,
    clientCallbackFunction: onWebRtcEvent
  }
});

WebRTC callback events

Callbacks receive objects with an event field.

A) Dialog / CTI-style events (primary for postMessages)

event

Description

What to read

agentInfo

SIP registration / login state

response.state (e.g. LOGIN), response.extension

outboundDialing

Outbound dial progress

response.dialog — states such as INITIATING, INITIATED, ALERTING, ACTIVE, FAILED, DROPPED; store dialog.id as dialogId

dialogState

Ongoing dialog updates

Same dialog state machine as outboundDialing

mediaStreamUpdate

Remote/local video or screenshare toggled

dialog.stream, streamStatus, eventRequest

mediaPermissionStatus

Browser mic/camera permission result

dialog.permissionType, permissionStatus

Error

Media or SIP failure

error / reason fields from callback

B) Legacy session events (still emitted by older helpers such as sendInvite)

event

Description

registered / registrationFailed

SIP register success or failure

Channel Creating

Dial started

session-accepted / session-progress / session-confirmed

Call progressing / answered

session-failed / session-rejected / session-terminated / session-ended / session-bye

Failure or teardown

session-iceConnectionDisconnected

ICE lost

Legacy WebRTC helpers (still exported)

NPM 6.2.0 still exports sendInvite, audioControl, videoControl, screenControl, terminateCurrentSession, closeSession, closeVideo, dialCall. Prefer postMessages for new web integrations; keep legacy helpers only if you already depend on them.

File upload example

JavaScript
const fd = new FormData();
fd.append("file", fileInput.files[0]);

customerSDK.uploadToFileEngine(fileServerUrl, fd, (res) => {
  if (res.isFileInvalid) {
    console.error(res.errorMessage);
    return;
  }
  // use res.name / type / size to build a FILE/IMAGE CIM message via sendChatMessage
});

Deprecated / incorrect names from older docs

Old documentation

Correct (v6.2.0)

establishConnection(serviceId, customerId, cb)

establishConnection(socketUrl, serviceId, customerId, cb)

sendMessage(data) for chat

sendChatMessage(data)

CHAT_REQUEST

CHAT_REQUESTED (socket emit)

uploadToFileEngine(data, cb)

uploadToFileEngine(fileServerUrl, formData, cb)

disconnect → type SOCKET_CONNECTED

disconnect → type SOCKET_DISCONNECTED

registerUser / hangUp

postMessages actions login / releaseCall

CDN sdk.js / sdk.min.js

Use package dist/index.js (and SIP bundle) or pinned GitHub release assets