1 | # Omnichannel Chat SDK 💬
|
2 |
|
3 | [![npm version](https://badge.fury.io/js/%40microsoft%2Fomnichannel-chat-sdk.svg)](https://badge.fury.io/js/%40microsoft%2Fomnichannel-chat-sdk)
|
4 | [![install size](https://packagephobia.com/badge?p=@microsoft/omnichannel-chat-sdk)](https://packagephobia.com/result?p=@microsoft/omnichannel-chat-sdk)
|
5 | ![Release CI](https://github.com/microsoft/omnichannel-chat-sdk/workflows/Release%20CI/badge.svg)
|
6 | ![npm](https://img.shields.io/npm/dm/@microsoft/omnichannel-chat-sdk)
|
7 |
|
8 | > ❗ We recommend using official release versions in production as listed [here](#releases). Support will be provided only on official versions.
|
9 |
|
10 | > 📢 Try out our new React component library [omnichannel-chat-widget](https://github.com/microsoft/omnichannel-chat-widget) with Chat SDK
|
11 |
|
12 | Headless Chat SDK to build your own chat widget against Dynamics 365 Omnichannel Services.
|
13 |
|
14 | Please make sure you have a chat widget configured before using this package or you can follow this [link](https://docs.microsoft.com/en-us/dynamics365/customer-service/add-chat-widget)
|
15 |
|
16 | ## Table of Contents
|
17 | - [Live Chat Widget vs. Chat SDK](#live-chat-widget-vs-chat-sdk)
|
18 | - [Releases](#releases)
|
19 | - [Installation](#installation)
|
20 | - [Installation on React Native](#installation-on-react-native)
|
21 | - [SDK Methods](#sdk-methods)
|
22 | - [Initialization](#initialization)
|
23 | - [Start Chat](#start-chat)
|
24 | - [End Chat](#end-chat)
|
25 | - [Get Pre-Chat Survey](#get-pre-chat-survey)
|
26 | - [Get Live Chat Config](#get-live-chat-config)
|
27 | - [Get Current Live Chat Context](#get-current-live-chat-context)
|
28 | - [Get Data Masking Rules](#get-data-masking-rules)
|
29 | - [Get Chat Reconnect Context](#get-chat-reconnect-context)
|
30 | - [Get Conversation Details](#get-conversation-details)
|
31 | - [Get Chat Token](#get-chat-token)
|
32 | - [Get Calling Token](#get-calling-token)
|
33 | - [Get Messages](#get-messages)
|
34 | - [Send Messages](#send-messages)
|
35 | - [On New Message](#on-new-message)
|
36 | - [On Typing Event](#on-typing-event)
|
37 | - [On Agent End Session](#on-agent-end-session)
|
38 | - [Send Typing Event](#send-typing-event)
|
39 | - [Email Live Chat Transcript](#email-live-chat-transcript)
|
40 | - [Get Live Chat Transcript](#get-live-chat-transcript)
|
41 | - [Upload File Attachment](#upload-file-attachment)
|
42 | - [Download File Attachment](#download-file-attachment)
|
43 | - [Create Chat Adapter](#create-chat-adapter)
|
44 | - [Get Voice & Video Calling](#get-voice--video-calling)
|
45 | - [Get Post Chat Survey Context](#get-post-chat-survey-context)
|
46 | - [Common Scenarios](#common-scenarios)
|
47 | - [Using BotFramework-WebChat](#using-botframework-webchat)
|
48 | - [Escalation to Voice & Video](#escalation-to-voice--video)
|
49 | - [Pre-Chat Survey](#pre-chat-survey)
|
50 | - [Post-Chat Survey](#post-chat-survey)
|
51 | - [Reconnect to existing Chat](#reconnect-to-existing-chat)
|
52 | - [Authenticated Chat](#authenticated-chat)
|
53 | - [Persistent Chat](#persistent-chat)
|
54 | - [Chat Reconnect with Authenticated User](#chat-reconnect-with-authenticated-user)
|
55 | - [Chat Reconnect with Unauthenticated User](#chat-reconnect-with-unauthenticated-user)
|
56 | - [Operating Hours](#operating-hours)
|
57 | - [Single Sign-on for Bots](/docs/scenarios/SINGLE_SIGN_ON_FOR_BOTS.md)
|
58 | - [Sample Apps](https://github.com/microsoft/omnichannel-chat-sdk-samples)
|
59 | - [Feature Comparisons](#feature-comparisons)
|
60 | - [Telemetry](#telemetry)
|
61 | - [Development Guide](docs/DEVELOPMENT_GUIDE.md)
|
62 | - [Troubleshooting Guide](docs/TROUBLESHOOTING_GUIDE.md)
|
63 |
|
64 | ## Live Chat Widget vs. Chat SDK
|
65 |
|
66 | Omnichannel offers an live chat widget (LCW) by default. You can use the Chat SDK to build your custom chat widget if:
|
67 | - You want to fully customize the user interface of the chat widget to conform with your branding.
|
68 | - You want to integrate Omnichannel in your mobile app using React Native.
|
69 | - You want to integrate additional functionalities that LCW does not offer.
|
70 | - Some other cool ideas. Please share with us on what you've achieved with the Chat SDK! 🙂
|
71 |
|
72 | ### Feature Comparisons
|
73 |
|
74 | | Feature | Live Chat Widget | Chat SDK | Notes |
|
75 | | ----- | ----- | ----- | ----- |
|
76 | | Bring Your Own Widget | ❌ | ✔ | |
|
77 | | Web Support | ✔ | ✔ |
|
78 | | React Native Support | ❌ | ✔ |
|
79 | | Escalation to Voice & Video | ✔ | ✔ | Only supported on Web |
|
80 | | Co-browse | ✔ | 3rd party add-on | Only supported on Web |
|
81 | | Screen Sharing | ✔ | 3rd party add-on | Only supported on Web |
|
82 | | Authenticated Chat | ✔ | ✔ |
|
83 | | Pre-chat Survey | ✔ | ✔ |
|
84 | | Post-chat Survey | ✔ | ✔ |
|
85 | | Download Transcript | ✔ | ✔ |
|
86 | | Email Transcript | ✔ | ✔ |
|
87 | | Data Masking | ✔ | ✔ |
|
88 | | File Attachments | ✔ | ✔ |
|
89 | | Custom Context | ✔ | ✔ |
|
90 | | Proactive Chat | ✔ | BYOI **\*** |
|
91 | | Persistent Chat | ✔ | ✔ |
|
92 | | Chat Reconnect | ✔ | ✔ |
|
93 | | Operating Hours | ✔ | ✔ |
|
94 | | Get Agent Availability | ✔ | ✔ |
|
95 | | Queue Position | ✔ | ✔ | No SDK method. Handled as *system message* |
|
96 | | Average Wait Time | ✔ | ✔ | No SDK method. Handled as *system message* |
|
97 |
|
98 | **\*** BYOI: Bring Your Own Implementation
|
99 |
|
100 | ## Releases
|
101 |
|
102 | New releases are published on a regular basis to ensure the product quality.
|
103 |
|
104 | | Version | Docs | Release Date | End of Support | Deprecated |
|
105 | | -- | -- | -- | -- | -- |
|
106 | | 1.6.2 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.6.2) | Dec 12th 2023 | Dec 12th 2024 | |
|
107 | | 1.6.1 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.6.1) | Dec 7th 2023 | Dec 7th 2024 | |
|
108 | | 1.6.0 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.6.0) | Dec 4th 2023 | Dec 4th 2024 | |
|
109 | | 1.5.7 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.5.7) | Nov 20th 2023 | Nov 20th 2024 | |
|
110 | | 1.5.6 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.5.6) | Nov 11th 2023 | Nov 11th 2024 | |
|
111 | | 1.5.5 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.5.5) | Oct 31st 2023 | Oct 31st 2024 | |
|
112 | | 1.5.4 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.5.4) | Oct 20th 2023 | Oct 20th 2024 | |
|
113 | | 1.5.3 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.5.3) | Oct 18th 2023 | Oct 18th 2024 | |
|
114 | | 1.5.2 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.5.2) | Oct 14th 2023 | Oct 14th 2024 | |
|
115 | | 1.5.1 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.5.1) | Oct 10th 2023 | Oct 10th 2024 | |
|
116 | | 1.5.0 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.5.0) | Sep 29th 2023 | Sep 29th 2024 | |
|
117 | | 1.4.7 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.4.7) | Sep 13th 2023 | Sep 13th 2024 | |
|
118 | | 1.4.6 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.4.6) | Aug 15th 2023 | Aug 15th 2024 | |
|
119 | | 1.4.5 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.4.5) | Aug 2nd 2023 | Aug 2nd 2024 | |
|
120 | | 1.4.4 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.4.4) | Jul 19th 2023 | Jul 19th 2024 | |
|
121 | | 1.4.3 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.4.3) | Jun 15th 2023 | Jun 15th 2024 | |
|
122 | | 1.4.2 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.4.2) | May 19th 2023 | May 19th 2024 | |
|
123 | | 1.4.1 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.4.1) | May 5th 2023 | May 5th 2024 | |
|
124 | | 1.4.0 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.4.0) | May 2nd 2023 | May 2nd 2024 | |
|
125 | | 1.3.0 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.3.0) | Apr 5th 2023 | Apr 5th 2024 | |
|
126 | | 1.2.0 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.2.0) | Nov 11th 2022 | Nov 11th 2023 | ✔️ |
|
127 | | 1.1.0 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.1.0) | Apr 15th 2021 | Apr 15th 2022 | ✔️ |
|
128 | | 1.0.0 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v1.0.0) | Oct 8th 2021 | Oct 8th 2022 | ✔️ |
|
129 | | 0.3.0 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v0.3.0) | Sep 3rd 2021 | Sep 3rd 2022 | ✔️ |
|
130 | | 0.2.0 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v0.2.0) | Apr 30th 2021 | Apr 30th 2022 | ✔️ |
|
131 | | 0.1.0 | [Release Notes](https://github.com/microsoft/omnichannel-chat-sdk/releases/tag/v0.1.0) | Oct 26th 2020 | Oct 26th 2021 | ✔️ |
|
132 |
|
133 | ## Installation
|
134 |
|
135 | ```
|
136 | npm install @microsoft/omnichannel-chat-sdk --save
|
137 | ```
|
138 |
|
139 | ## Installation on React Native
|
140 |
|
141 | The following steps will be required to run Omnichannel Chat SDK on React Native:
|
142 |
|
143 | 1. Install `node-libs-react-native`
|
144 | ```
|
145 | npm install node-libs-react-native --save-dev
|
146 | ```
|
147 |
|
148 | 1. Install `react-native-randomBytes`
|
149 | ```
|
150 | npm install react-native-randombytes --save-dev
|
151 | ```
|
152 |
|
153 | 1. Install `react-native-get-random-values`
|
154 | ```
|
155 | npm install react-native-get-random-values --save-dev
|
156 | ```
|
157 |
|
158 | 1. Install `react-native-url-polyfill`
|
159 | ```
|
160 | npm install react-native-url-polyfill --save-dev
|
161 | ```
|
162 |
|
163 | 1. Install `@azure/core-asynciterator-polyfill`
|
164 | ```
|
165 | npm install @azure/core-asynciterator-polyfill --save-dev
|
166 | ```
|
167 |
|
168 | 1. Update *metro.config.js* to use React Native compatible Node Core modules
|
169 | ```ts
|
170 | module.exports = {
|
171 | // ...
|
172 | resolver: {
|
173 | extraNodeModules: {
|
174 | ...require('node-libs-react-native'),
|
175 | net: require.resolve('node-libs-react-native/mock/net'),
|
176 | tls: require.resolve('node-libs-react-native/mock/tls')
|
177 | }
|
178 | }
|
179 | };
|
180 | ```
|
181 |
|
182 | 1. Add following *import* on top of your entry point file
|
183 | ```ts
|
184 | import 'node-libs-react-native/globals';
|
185 | import 'react-native-get-random-values';
|
186 | import 'react-native-url-polyfill/auto';
|
187 | import '@azure/core-asynciterator-polyfill';
|
188 | ```
|
189 |
|
190 | ## SDK Methods
|
191 |
|
192 | ### Initialization
|
193 |
|
194 | It handles the initialization of ChatSDK internal data.
|
195 |
|
196 | ```ts
|
197 | import OmnichannelChatSDK from '@microsoft/omnichannel-chat-sdk';
|
198 |
|
199 | const omnichannelConfig = {
|
200 | orgUrl: "",
|
201 | orgId: "",
|
202 | widgetId: ""
|
203 | };
|
204 |
|
205 | const chatSDKConfig = { // Optional
|
206 | dataMasking: {
|
207 | disable: false,
|
208 | maskingCharacter: '#'
|
209 | }
|
210 | };
|
211 |
|
212 | const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
|
213 |
|
214 | const optionalParams = {
|
215 | getLiveChatConfigOptionalParams: {
|
216 | sendCacheHeaders: false // Whether to send Cache-Control HTTP header to GetChatConfig call
|
217 | }
|
218 | };
|
219 |
|
220 | await chatSDK.initialize(optionalParams);
|
221 | ```
|
222 |
|
223 | ### Start Chat
|
224 |
|
225 | It starts an Omnichannel conversation.
|
226 |
|
227 | ```ts
|
228 | const customContext = {
|
229 | 'contextKey1': {'value': 'contextValue1', 'isDisplayable': true},
|
230 | 'contextKey2': {'value': 12.34, 'isDisplayable': false},
|
231 | 'contextKey3': {'value': true}
|
232 | };
|
233 |
|
234 | const optionalParams = {
|
235 | preChatResponse: '', // PreChatSurvey response
|
236 | liveChatContext: {}, // EXISTING chat context data
|
237 | customContext, // Custom Context
|
238 | sendDefaultInitContext: true // Send default init context ⚠️ Web only
|
239 | };
|
240 |
|
241 | await chatSDK.startChat(optionalParams);
|
242 | ```
|
243 |
|
244 | ### End Chat
|
245 |
|
246 | It ends the current Omnichannel conversation.
|
247 |
|
248 | ```ts
|
249 | await chatSDK.endChat();
|
250 | ```
|
251 |
|
252 | ### Get Pre-Chat Survey
|
253 |
|
254 | It gets the Pre-Chat Survey from Live Chat Config. Pre-Chat Survey is in Adaptive Card format.
|
255 |
|
256 | `Option 1`
|
257 | ```ts
|
258 | const preChatSurvey = await getPreChatSurvey(); // Adaptive Cards JSON payload data
|
259 | ```
|
260 | `Option 2`
|
261 | ```ts
|
262 | const parseToJSON = false;
|
263 | const preChatSurvey = await getPreChatSurvey(parseToJSON); // Adaptive Cards payload data as string
|
264 | ```
|
265 |
|
266 | ### Get Live Chat Config
|
267 |
|
268 | It fetches the Live Chat Config.
|
269 |
|
270 | ```ts
|
271 | const liveChatConfig = await chatSDK.getLiveChatConfig();
|
272 | ```
|
273 |
|
274 | ### Get Current Live Chat Context
|
275 |
|
276 | It gets the current live chat context information to be used to reconnect to the same conversation.
|
277 |
|
278 | ```ts
|
279 | const liveChatContext = await chatSDK.getCurrentLiveChatContext();
|
280 | ```
|
281 |
|
282 | ### Get Data Masking Rules
|
283 |
|
284 | It gets the active data masking rules from Live Chat Config.
|
285 |
|
286 | ```ts
|
287 | const dataMaskingRules = await chatSDK.getDataMaskingRules();
|
288 | ```
|
289 |
|
290 | ### Get Chat Reconnect Context
|
291 |
|
292 | It gets the current reconnectable chat context information to connect to a previous existing chat session.
|
293 |
|
294 | `Reconnection options` is required. See [documentation](https://docs.microsoft.com/en-us/dynamics365/customer-service/configure-reconnect-chat?tabs=customerserviceadmincenter#enable-reconnection-to-a-previous-chat-session)
|
295 |
|
296 | ```ts
|
297 | const optionalParams = {
|
298 | reconnectId: '', // reconnect Id
|
299 | };
|
300 |
|
301 | const chatReconnectContext = await chatSDK.getChatReconnectContext(optionalParams);
|
302 | ```
|
303 |
|
304 | ### Get Conversation Details
|
305 |
|
306 | It gets the details of the current conversation such as its state & when the agent joined the conversation.
|
307 |
|
308 | ```ts
|
309 | const optionalParams = {
|
310 | liveChatContext: {}, // EXISTING chat context data
|
311 | };
|
312 |
|
313 | const conversationDetails = await chatSDK.getConversationDetails(optionalParams);
|
314 | ```
|
315 |
|
316 | ### Get chat Token
|
317 |
|
318 | It gets the chat token used to initiates a chat with Omnichannel messaging client.
|
319 |
|
320 | ```ts
|
321 | const chatToken = await chatSDK.getChatToken();
|
322 | ```
|
323 |
|
324 | ### Get Calling Token
|
325 |
|
326 | It gets the calling token used to initiates a Voice & Video Call.
|
327 |
|
328 | ```ts
|
329 | const callingToken = await chatSDK.getCallingToken();
|
330 | ```
|
331 |
|
332 | ### Get Messages
|
333 |
|
334 | It gets all the messages of the current conversation.
|
335 |
|
336 | ```ts
|
337 | const messages = await chatSDK.getMessages();
|
338 | ```
|
339 |
|
340 | ### Send Messages
|
341 |
|
342 | It sends a message to Omnichannel.
|
343 |
|
344 | ```ts
|
345 | import {DeliveryMode, MessageContentType, MessageType, PersonType} from '@microsoft/omnichannel-chat-sdk';
|
346 |
|
347 | ...
|
348 |
|
349 | const displayName = "Contoso"
|
350 | const message = "Sample message from customer";
|
351 | const messageToSend = {
|
352 | content: message
|
353 | };
|
354 |
|
355 | await chatSDK.sendMessage(messageToSend);
|
356 | ```
|
357 |
|
358 | ### On New Message
|
359 |
|
360 | It subscribes to new incoming messages of the current conversation such as system messages, client messages, agent messages, adaptive cards and attachments.
|
361 |
|
362 | ```ts
|
363 | const optionalParams = {
|
364 | rehydrate: true, // Rehydrate all previous messages of existing conversation (false by default)
|
365 | }
|
366 |
|
367 | chatSDK.onNewMessage((message) => {
|
368 | console.log(`[NewMessage] ${message.content}`);
|
369 | console.log(message);
|
370 | }, optionalParams);
|
371 | ```
|
372 | ### On Typing Event
|
373 |
|
374 | It subscribes to agent typing event.
|
375 |
|
376 | ```ts
|
377 | chatSDK.onTypingEvent(() => {
|
378 | console.log("Agent is typing...");
|
379 | })
|
380 | ```
|
381 |
|
382 | ### On Agent End Session
|
383 |
|
384 | It subscribes to agent ending the session of the conversation.
|
385 |
|
386 | ```ts
|
387 | chatSDK.onAgentEndSession(() => {
|
388 | console.log("Session ended!");
|
389 | });
|
390 | ```
|
391 |
|
392 | ### Send Typing Event
|
393 |
|
394 | It sends a customer typing event.
|
395 |
|
396 | ```ts
|
397 | await chatSDK.sendTypingEvent();
|
398 | ```
|
399 |
|
400 | ### Email Live Chat Transcript
|
401 |
|
402 | It sends an email of the live chat transcript.
|
403 |
|
404 | ```ts
|
405 | const body = {
|
406 | emailAddress: 'contoso@microsoft.com',
|
407 | attachmentMessage: 'Attachment Message'
|
408 | };
|
409 | await chatSDK.emailLiveChatTranscript(body);
|
410 | ```
|
411 |
|
412 | ### Get Live Chat Transcript
|
413 |
|
414 | It fetches the current conversation transcript data in JSON.
|
415 |
|
416 | ```ts
|
417 | const optionalParams = {
|
418 | liveChatContext: {}, // EXISTING chat context data
|
419 | };
|
420 |
|
421 | await chatSDK.getLiveChatTranscript(optionalParams);
|
422 | ```
|
423 |
|
424 | ### Upload File Attachment
|
425 |
|
426 | It sends a file attachment to the current conversation.
|
427 |
|
428 | ```ts
|
429 | const fileInfo = {
|
430 | name: '',
|
431 | type: '',
|
432 | size: '',
|
433 | data: ''
|
434 | };
|
435 | await chatSDK.uploadFileAttachment(fileInfo);
|
436 | ```
|
437 |
|
438 | ### Download File Attachment
|
439 |
|
440 | It downloads the file attachment of the incoming message as a Blob response.
|
441 |
|
442 | ```ts
|
443 | const blobResponse = await chatsdk.downloadFileAttachment(message.fileMetadata);
|
444 |
|
445 | ...
|
446 |
|
447 | // React Native implementation
|
448 | const fileReaderInstance = new FileReader();
|
449 | fileReaderInstance.readAsDataURL(blobResponse);
|
450 | fileReaderInstance.onload = () => {
|
451 | const base64data = fileReaderInstance.result;
|
452 | return <Image source={{uri: base64data}}/>
|
453 | }
|
454 | ```
|
455 |
|
456 | ### Create Chat Adapter
|
457 |
|
458 | > :warning: Currently supported on web only
|
459 |
|
460 | It creates a chat adapter to use with [BotFramework-WebChat](https://github.com/microsoft/BotFramework-WebChat).
|
461 |
|
462 | ```ts
|
463 | const chatAdapter = await chatSDK.createChatAdapter();
|
464 | ```
|
465 |
|
466 | ### Get Voice & Video Calling
|
467 |
|
468 | > :warning: Currently supported on web only
|
469 |
|
470 | > :warning: Please ensure voice & video call is stopped before leveraging endChat SDK method
|
471 |
|
472 | It fetches the SDK for Escalation to Voice & Video.
|
473 |
|
474 | ```ts
|
475 | try {
|
476 | const VoiceVideoCallingSDK = await chatSDK.getVoiceVideoCalling();
|
477 | console.log("VoiceVideoCalling loaded");
|
478 | } catch (e) {
|
479 | console.log(`Failed to load VoiceVideoCalling: ${e}`);
|
480 |
|
481 | if (e.message === 'UnsupportedPlatform') {
|
482 | // Voice Video Calling feature is not supported on this platform
|
483 | }
|
484 |
|
485 | if (e.message === 'FeatureDisabled') {
|
486 | // Voice Video Calling feature is disabled on admin side
|
487 | }
|
488 | }
|
489 | ```
|
490 | ### Get Post Chat Survey Context
|
491 |
|
492 | It gets the participant type that should be used for the survey and both the default and bot survey details.
|
493 |
|
494 | ```ts
|
495 | const postChatSurveyContext = await chatSDK.getPostChatSurveyContext();
|
496 | ```
|
497 |
|
498 | ### Get Agent Availability
|
499 |
|
500 | It gets information on whether a queue is available, and whether there are agents available in that queue, as well as queue position and average wait time. This call only supports authenticated chat.
|
501 |
|
502 | ```ts
|
503 | const agentAvailability = await chatSDK.getAgentAvailability();
|
504 | ```
|
505 |
|
506 | ## Common Scenarios
|
507 |
|
508 | ### Pre-Chat Survey
|
509 |
|
510 | > See https://docs.microsoft.com/en-us/dynamics365/customer-service/configure-pre-chat-survey?tabs=customerserviceadmincenter on how to set up pre-conversation surveys
|
511 |
|
512 | ```ts
|
513 | import * as AdaptiveCards, { Action } from "adaptivecards";
|
514 |
|
515 | ...
|
516 |
|
517 | const preChatSurvey = await chatSDK.getPreChatSurvey();
|
518 |
|
519 | ...
|
520 |
|
521 | // Web implementation
|
522 | const renderPreChatSurvey = () => {
|
523 | const adaptiveCard = new AdaptiveCards.AdaptiveCard();
|
524 | adaptiveCard.parse(preChatSurvey); // Parses Adaptive Card JSON data
|
525 | adaptiveCard.onExecuteAction = async (action: Action) => { // Adaptive Card event handler
|
526 | const preChatResponse = (action as any).data;
|
527 | const optionalParams: any = {};
|
528 | if (preChatResponse) {
|
529 | optionalParams.preChatResponse = preChatResponse;
|
530 | }
|
531 | await chatSDK.startChat(optionalParams);
|
532 | }
|
533 |
|
534 | const renderedCard = adaptiveCard.render(); // Renders as HTML element
|
535 | return <div ref={(n) => { // Returns React element
|
536 | n && n.firstChild && n.removeChild(n.firstChild); // Removes duplicates fix
|
537 | renderedCard && n && n.appendChild(renderedCard);
|
538 | }} />
|
539 | }
|
540 |
|
541 | ```
|
542 |
|
543 | ### Post-Chat Survey
|
544 |
|
545 | > See https://docs.microsoft.com/en-us/dynamics365/customer-service/configure-post-conversation-survey?tabs=customerserviceadmincenter on how to set up post-conversation surveys
|
546 |
|
547 | > ❗ `chatSDK.getPostChatSurveyContext()` needs to be called before `chatSDK.endChat()` is called
|
548 |
|
549 | ```ts
|
550 | // 1. Start chat
|
551 | await chatSDK.startChat();
|
552 |
|
553 | // 2. Save post chat survey context before ending chat
|
554 | try {
|
555 | const context = await chatSDK.getPostChatSurveyContext();
|
556 | if (context.participantJoined) { // participantJoined will be true if an agent has joined the conversation, or a bot has joined the conversation and the bot survey flag has been turned on on the admin side.
|
557 | // formsProLocale is the default language you have set on the CustomerVoice portal. You can override this url parameter with any locale that CustomerVoice supports.
|
558 | // If "&lang=" is not set on the url, the locale will be English.
|
559 | const link = context.participantType === "Bot" ? context.botSurveyInviteLink : context.surveyInviteLink;
|
560 | const locale = context.participantType === "Bot" ? context.botFormsProLocale : context.formsProLocale;
|
561 | const linkToSend = link + "&lang=" + locale;
|
562 | // This link is accessible and will redirect to the survey page. Use it as you see fit.
|
563 | }
|
564 | } catch (ex) {
|
565 | // If the post chat should not be shown by any reason (e.g. post chat is not enabled), promise will be rejected.
|
566 | }
|
567 |
|
568 | // 3. End chat
|
569 | await chatSDK.endChat();
|
570 |
|
571 | // 4. Display Post Chat
|
572 | ```
|
573 |
|
574 | ### Reconnect to existing Chat
|
575 |
|
576 | ```ts
|
577 | await chatSDK.startChat(); // Starts NEW chat
|
578 |
|
579 | const liveChatContext = await chatSDK.getCurrentLiveChatContext(); // Gets chat context
|
580 |
|
581 | cache.saveChatContext(liveChatContext); // Custom logic to save chat context to cache
|
582 |
|
583 | ...
|
584 |
|
585 | // Page/component reloads, ALL previous states are GONE
|
586 |
|
587 | ...
|
588 |
|
589 | const liveChatContext = cache.loadChatContext() // Custom logic to load chat context from cache
|
590 |
|
591 | const optionalParams = {};
|
592 | optionalParams.liveChatContext = liveChatContext;
|
593 |
|
594 | await chatSDK.startChat(optionalParams); // Reconnects to EXISTING chat
|
595 |
|
596 | ...
|
597 |
|
598 | const messages = await chatSDK.getMessages(); // Gets all messages from EXISTING chat
|
599 | messages.reverse().forEach((message: any) => renderMessage(message)); // Logic to render all messages to UI
|
600 | ```
|
601 |
|
602 | ### Authenticated Chat
|
603 |
|
604 | > See https://docs.microsoft.com/en-us/dynamics365/customer-service/create-chat-auth-settings?tabs=customerserviceadmincenter#create-a-chat-authentication-setting-record on how to set up an authenticated chat
|
605 |
|
606 | ```ts
|
607 | const chatSDKConfig = {
|
608 | getAuthToken: async () => {
|
609 | const response = await fetch("http://contosohelp.com/token");
|
610 | if (response.ok) {
|
611 | return await response.text();
|
612 | }
|
613 | else {
|
614 | return null
|
615 | }
|
616 | }
|
617 | }
|
618 |
|
619 | const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
|
620 | await chatSDK.initialize();
|
621 |
|
622 | // from this point, this acts like a regular chat widget
|
623 | ```
|
624 |
|
625 | ### Persistent Chat
|
626 |
|
627 | > See https://docs.microsoft.com/en-us/dynamics365/customer-service/persistent-chat on how to set up persistent chat
|
628 |
|
629 | ```ts
|
630 | const chatSDKConfig = {
|
631 | persistentChat: {
|
632 | disable: false,
|
633 | tokenUpdateTime: 21600000
|
634 | },
|
635 | getAuthToken: async () => {
|
636 | const response = await fetch("http://contosohelp.com/token");
|
637 | if (response.ok) {
|
638 | return await response.text();
|
639 | }
|
640 | else {
|
641 | return null
|
642 | }
|
643 | }
|
644 | }
|
645 |
|
646 | const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
|
647 | await chatSDK.initialize();
|
648 |
|
649 | // from this point, this acts like a persistent chat
|
650 | ```
|
651 | ### Chat Reconnect with Authenticated User
|
652 |
|
653 | > See https://docs.microsoft.com/en-us/dynamics365/customer-service/configure-reconnect-chat?tabs=customerserviceadmincenter#enable-reconnection-to-a-previous-chat-session on how to set up chat reconnect
|
654 |
|
655 | ```ts
|
656 | const chatSDKConfig = {
|
657 | chatReconnect: {
|
658 | disable: false,
|
659 | },
|
660 | getAuthToken: async () => {
|
661 | const response = await fetch("http://contosohelp.com/token");
|
662 | if (response.ok) {
|
663 | return await response.text();
|
664 | }
|
665 | else {
|
666 | return null
|
667 | }
|
668 | }
|
669 | }
|
670 |
|
671 | const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
|
672 | await chatSDK.initialize();
|
673 |
|
674 | ...
|
675 |
|
676 | const chatReconnectContext = await chatSDK.getChatReconnectContext();
|
677 |
|
678 | if (chatReconnectContext.reconnectId) {
|
679 | // Add UX with options to reconnect to previous existing chat or start new chat
|
680 | }
|
681 |
|
682 | // Reconnect chat option
|
683 | const optionalParams = {};
|
684 | optionalParams.reconnectId = chatReconnectContext.reconnectId;
|
685 | chatSDK.startChat(optionalParams);
|
686 |
|
687 | // Start new chat option
|
688 | chatSDK.startChat();
|
689 | ```
|
690 |
|
691 | ### Chat Reconnect with Unauthenticated User
|
692 |
|
693 | > See https://docs.microsoft.com/en-us/dynamics365/customer-service/configure-reconnect-chat?tabs=customerserviceadmincenter#enable-reconnection-to-a-previous-chat-session on how to set up chat reconnect
|
694 |
|
695 | ```ts
|
696 | const chatSDKConfig = {
|
697 | chatReconnect: {
|
698 | disable: false,
|
699 | },
|
700 | }
|
701 |
|
702 | const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
|
703 | await chatSDK.initialize();
|
704 |
|
705 | ....
|
706 |
|
707 | const optionalParams: any = {};
|
708 |
|
709 | // Retrieve reconnect id from the URL
|
710 | const urlParams = new URLSearchParams(window.location.search);
|
711 | const reconnectId = urlParams.get('oc.reconnectid');
|
712 |
|
713 | const params = {
|
714 | reconnectId
|
715 | };
|
716 |
|
717 | // Validate reconnect id
|
718 | const chatReconnectContext = await chatSDK.getChatReconnectContext(params);
|
719 |
|
720 | // If the reconnect id is invalid or expired, redirect URL if there is any URL set in the configuration
|
721 | if (chatReconnectContext.redirectURL) {
|
722 | window.location.replace(chatReconnectContext.redirectURL);
|
723 | }
|
724 |
|
725 | // Valid reconnect id, reconnect to previous chat
|
726 | if (chatReconnectContext.reconnectId) {
|
727 | await chatSDK.startChat({
|
728 | reconnectId: chatReconnectContext.reconnectId
|
729 | });
|
730 | } else { // Reconnect id from URL is not valid, start new chat session
|
731 | await chatSDK.startChat();
|
732 | }
|
733 | ```
|
734 |
|
735 | ### Operating Hours
|
736 |
|
737 | > See https://docs.microsoft.com/en-us/dynamics365/customer-service/create-operating-hours?tabs=customerserviceadmincenter on how to set up operating hours
|
738 |
|
739 | ```ts
|
740 | const chatConfig = await chatSDK.getLiveChatConfig();
|
741 | const {LiveWSAndLiveChatEngJoin: liveWSAndLiveChatEngJoin} = liveChatConfig;
|
742 | const {OutOfOperatingHours: outOfOperatingHours} = liveWSAndLiveChatEngJoin;
|
743 |
|
744 | if (outOfOperatingHours === "True") {
|
745 | // Handles UX on Out of Operating Hours
|
746 | } else {
|
747 | await chatSDK.startChat();
|
748 | // Renders Custom Chat Widget
|
749 | }
|
750 | ```
|
751 |
|
752 | ### Using [BotFramework-WebChat](https://github.com/microsoft/BotFramework-WebChat)
|
753 | > :warning: Currently supported on web only
|
754 |
|
755 | Minimum Requirement Checklist
|
756 | 1. [ ] Initialize ChatSDK
|
757 | 1. [ ] Start new conversation
|
758 | 1. [ ] Create Chat Adapter
|
759 | 1. [ ] Create WebChat store with default middlewares
|
760 | 1. [ ] Send Default Channel Message Tags using Store Middleware (See [here](/docs//DEVELOPMENT_GUIDE.md#send-default-channel-message-tags-using-store-middleware)) ❗ Required
|
761 | 1. [ ] Render WebChat
|
762 |
|
763 | ```ts
|
764 | import OmnichannelChatSDK from '@microsoft/omnichannel-chat-sdk';
|
765 | import ReactWebChat, {createStore} from 'botframework-webchat';
|
766 |
|
767 | // 1. ChatSDK Initialization
|
768 | const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig);
|
769 | await chatSDK.initialize();
|
770 |
|
771 | // 2. Start new conversation
|
772 | await chatSDK.startChat();
|
773 |
|
774 | // 3. Create chat adapter
|
775 | const chatAdapter = await chatSDK.createChatAdapter();
|
776 |
|
777 | // 4. Create WebChat store with middlewares
|
778 | const store = createStore(
|
779 | {}, // initial state
|
780 | sendDefaultMessagingTagsMiddleware // ❗ Required
|
781 | );
|
782 |
|
783 | // 5. Render WebChat
|
784 | <ReactWebChat
|
785 | store={store}
|
786 | userID="teamsvisitor"
|
787 | directLine={chatAdapter}
|
788 | sendTypingIndicator={true}
|
789 | />
|
790 | ```
|
791 |
|
792 | ### Escalation to Voice & Video
|
793 | > :warning: Currently supported on web only
|
794 |
|
795 | > See https://docs.microsoft.com/en-us/dynamics365/customer-service/call-options-visual-engagement on how to set up calling options
|
796 |
|
797 | ```ts
|
798 | import OmnichannelChatSDK from '@microsoft/omnichannel-chat-sdk';
|
799 |
|
800 | ...
|
801 |
|
802 | const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
|
803 | await chatSDK.initialize();
|
804 |
|
805 | let VoiceVideoCallingSDK;
|
806 | try {
|
807 | VoiceVideoCallingSDK = await chatSDK.getVoiceVideoCalling();
|
808 | console.log("VoiceVideoCalling loaded");
|
809 | } catch (e) {
|
810 | console.log(`Failed to load VoiceVideoCalling: ${e}`);
|
811 |
|
812 | if (e.message === 'UnsupportedPlatform') {
|
813 | // Voice Video Calling feature is not supported on this platform
|
814 | }
|
815 |
|
816 | if (e.message === 'FeatureDisabled') {
|
817 | // Voice Video Calling feature is disabled on admin side
|
818 | }
|
819 | }
|
820 |
|
821 | await chatSDK.startChat();
|
822 |
|
823 | const chatToken: any = await chatSDK.getChatToken();
|
824 |
|
825 | // Initialize only if VoiceVideoCallingSDK is defined
|
826 | if (VoiceVideoCallingSDK) {
|
827 | try {
|
828 | await VoiceVideoCallingSDK.initialize({
|
829 | chatToken,
|
830 | selfVideoHTMLElementId: 'selfVideo', // HTML element id where video stream of the agent will be rendered
|
831 | remoteVideoHTMLElementId: 'remoteVideo', // HTML element id where video stream of the customer will be rendered
|
832 | OCClient: chatSDK.OCClient
|
833 | });
|
834 | } catch (e) {
|
835 | console.error("Failed to initialize VoiceVideoCalling!");
|
836 | }
|
837 |
|
838 | // Triggered when there's an incoming call
|
839 | VoiceVideoCallingSDK.onCallAdded(() => {
|
840 | ...
|
841 | });
|
842 |
|
843 | // Triggered when local video stream is available (e.g.: Local video added succesfully in selfVideoHTMLElement)
|
844 | VoiceVideoCallingSDK.onLocalVideoStreamAdded(() => {
|
845 | ...
|
846 | });
|
847 |
|
848 | // Triggered when local video stream is unavailable (e.g.: Customer turning off local video)
|
849 | VoiceVideoCallingSDK.onLocalVideoStreamRemoved(() => {
|
850 | ...
|
851 | });
|
852 |
|
853 | // Triggered when remote video stream is available (e.g.: Remote video added succesfully in remoteVideoHTMLElement)
|
854 | VoiceVideoCallingSDK.onRemoteVideoStreamAdded(() => {
|
855 | ...
|
856 | });
|
857 |
|
858 | // Triggered when remote video stream is unavailable (e.g.: Agent turning off remote video)
|
859 | VoiceVideoCallingSDK.onRemoteVideoStreamRemoved(() => {
|
860 | ...
|
861 | });
|
862 |
|
863 | // Triggered when current call has ended or disconnected regardless the party
|
864 | VoiceVideoCalling.onCallDisconnected(() => {
|
865 | ...
|
866 | });
|
867 |
|
868 | // Check if microphone is muted
|
869 | const isMicrophoneMuted = VoiceVideoCallingSDK.isMicrophoneMuted();
|
870 |
|
871 | // Check if remote video is available
|
872 | const isRemoteVideoEnabled = VoiceVideoCallingSDK.isRemoteVideoEnabled();
|
873 |
|
874 | // Check if local video is available
|
875 | const isLocalVideoEnabled = VoiceVideoCallingSDK.isLocalVideoEnabled();
|
876 |
|
877 | // Accepts incoming call
|
878 | const acceptCallConfig = {
|
879 | withVideo: true // Accept call with/without video stream
|
880 | };
|
881 | await VoiceVideoCallingSDK.acceptCall(acceptCallConfig);
|
882 |
|
883 | // Rejects incoming call
|
884 | await VoiceVideoCallingSDK.rejectCall();
|
885 |
|
886 | // Ends/Stops current call
|
887 | await VoiceVideoCallingSDK.stopCall();
|
888 |
|
889 | // Mute/Unmute current call
|
890 | await VoiceVideoCallingSDK.toggleMute()
|
891 |
|
892 | // Display/Hide local video of current call
|
893 | await VoiceVideoCallingSDK.toggleLocalVideo()
|
894 |
|
895 | // Clean up VoiceVideoCallingSDK (e.g.: Usually called when customer ends chat session)
|
896 | VoiceVideoCallingSDK.close();
|
897 | }
|
898 | ```
|
899 |
|
900 | ## Feature Comparisons
|
901 |
|
902 | ### Web
|
903 | | | Custom Control | WebChat Control |
|
904 | | --- | --- | --- |
|
905 | | **Features** | | |
|
906 | | Chat Widget UI | Not provided | Basic chat client provided |
|
907 | | Data Masking | Embedded | Requires `Data Masking Middleware` implementation |
|
908 | | Send Typing indicator | Embedded | Requires `sendTypingIndicator` flag set to `true` |
|
909 | | PreChat Survey | Requires Adaptive Cards renderer | Requires Adaptive Cards renderer
|
910 | | Display Attachments | Requires implementation | Basic interface provided & Customizable |
|
911 | | Incoming messages handling | IC3 protocol message data | DirectLine activity data |
|
912 |
|
913 | ### React Native
|
914 | | | Custom Control | Gifted Chat Control | WebChat Control |
|
915 | | --- | --- | --- | --- |
|
916 | | **Features** | | | Currently not supported |
|
917 | | Chat Widget UI | Not provided | Basic chat client provided | X |
|
918 | | Data Masking | Embedded | Embedded | X |
|
919 | | Send Typing indicator | Embedded | Requires Implementation | X |
|
920 | | PreChat Survey | Requires Adaptive Cards renderer | Requires Adaptive Cards renderer | X |
|
921 | | Display Attachments | Requires implementation| Embedded | X |
|
922 | | Incoming messages handling |IC3 protocol message data | IC3 protocol message data | X |
|
923 |
|
924 | ## Telemetry
|
925 |
|
926 | Omnichannel Chat SDK collects telemetry by default to improve the feature’s capabilities, reliability, and performance over time by helping Microsoft understand usage patterns, plan new features, and troubleshoot and fix problem areas.
|
927 |
|
928 | Some of the data being collected are the following:
|
929 |
|
930 | | Field | Sample |
|
931 | | --- | --- |
|
932 | | Organization Id | `e00e67ee-a60e-4b49-b28c-9d279bf42547` |
|
933 | | Organization Url | `org60082947.crm.oc.crmlivetie.com` |
|
934 | | Widget Id | `1893e4ae-2859-4ac4-9cf5-97cffbb9c01b` |
|
935 | | Browser Name | `Edge` |
|
936 | | Os Name | `Windows` |
|
937 | | Anonymized IP Address (last octet redacted) | `19.207.000.000` |
|
938 |
|
939 | If your organization is concerned about the data collected by the Chat SDK, you have the option to turn off automatic data collection by adding a flag in the `ChatSDKConfig`.
|
940 |
|
941 | ```ts
|
942 | const omnichannelConfig = {
|
943 | orgUrl: "",
|
944 | orgId: "",
|
945 | widgetId: ""
|
946 | };
|
947 |
|
948 | const chatSDKConfig = {
|
949 | telemetry: {
|
950 | disable: true // Disable telemetry
|
951 | }
|
952 | };
|
953 |
|
954 | const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
|
955 | await chatSDK.initialize();
|
956 | ```
|
957 |
|
958 | # Contributing
|
959 |
|
960 | This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
961 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
|
962 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
|
963 |
|
964 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide
|
965 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
|
966 | provided by the bot. You will only need to do this once across all repos using our CLA.
|
967 |
|
968 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
969 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
|
970 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|