Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

@microsoft/omnichannel-chat-sdk

microsoft15.3kMIT1.11.7-main.ac96468TypeScript support: included

Microsoft Omnichannel Chat SDK

SDK, chat, livechat, support, bot, headless, customer

readme

Omnichannel Chat SDK 💬

npm version install size Release CI npm

❗ We recommend using official release versions in production as listed here. Support will be provided only on official versions.

📢 Try out our new React component library omnichannel-chat-widget with Chat SDK

Headless Chat SDK to build your own chat widget against Dynamics 365 Omnichannel Services.

Please make sure you have a chat widget configured before using this package or you can follow this link

Table of Contents

Live Chat Widget vs. Chat SDK

Omnichannel offers a live chat widget (LCW) by default. You can use the Chat SDK to build your custom chat widget if:

  • You want to fully customize the user interface of the chat widget to conform with your branding.
  • You want to integrate Omnichannel into your mobile app using React Native.
  • You want to integrate additional functionalities that LCW does not offer.
  • Some other cool ideas. Please share with us what you've achieved with the Chat SDK! 🙂

Feature Comparisons

Feature Live Chat Widget Chat SDK Notes
Bring Your Own Widget
Web Support
React Native Support
Escalation to Voice & Video Only supported on Web
Co-browse 3rd party add-on Only supported on Web
Screen Sharing 3rd party add-on Only supported on Web
Authenticated Chat
Pre-chat Survey
Post-chat Survey
Download Transcript
Email Transcript
Data Masking
File Attachments
Custom Context
Proactive Chat BYOI *
Persistent Chat
Chat Reconnect
Operating Hours
Get Agent Availability
Queue Position No SDK method. Handled as system message
Average Wait Time No SDK method. Handled as system message

* BYOI: Bring Your Own Implementation

Releases

New releases are published on a regular basis to ensure the product quality.

for a detailed tracking of the releases, please refer to the Changelog document

Important Note: Versions below 1.11.0 will not be supported after November 1st, 2025. Please update to recent versions to ensure you have the latest features and bug fixes.

Version Docs Release Date End of Support Deprecated
1.11.4 Release Notes Jul 17th 2025 Jul 17th 2026
1.11.3 Release Notes Jul 14th 2025 Jul 14th 2026
1.11.2 Release Notes Jun 24th 2025 Jun 24th 2026
1.11.1 Release Notes Jun 5th 2025 Jun 5th 2026
1.11.0 Release Notes May 27th 2025 May 27th 2026

Installation

npm install @microsoft/omnichannel-chat-sdk --save

Installation on React Native

Important Note:

  • For React Native versions 0.71 and above: Steps 1, 2, 3 are required only for iOS. Not needed for Android.
  • For React Native versions below 0.71: Steps 1, 2, 3 are required for both Android and iOS.

Steps

  1. Install node-libs-react-native

     npm install node-libs-react-native --save-dev
  2. Install react-native-randombytes

     npm install react-native-randombytes --save-dev
  3. Install react-native-get-random-values

     npm install react-native-get-random-values --save-dev
  4. Install react-native-url-polyfill

     npm install react-native-url-polyfill --save-dev
  5. Install @azure/core-asynciterator-polyfill

     npm install @azure/core-asynciterator-polyfill --save-dev

    iOS and Android Platforms

React Native Version Libraries iOS Android
0.71 and above |
| node-libs-react-native ✅ Yes ❌ No
| react-native-randombytes ✅ Yes ❌ No
| react-native-get-random-values ✅ Yes ❌ No
| react-native-url-polyfill ✅ Yes ✅ Yes
| @azure/core-asynciterator-polyfill ✅ Yes ✅ Yes

Below 0.71 version you need to add all above libraries.

Required file changes

  1. In metro.config.js
  2. Update metro.config.js to use React Native compatible Node Core modules.
      const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
      const nodeLibs = require('node-libs-react-native'); // Import node-libs-react-native
      const config = {
        resolver: {
          extraNodeModules: {
            ...nodeLibs,
            net: require.resolve('node-libs-react-native/mock/net'),
            tls: require.resolve('node-libs-react-native/mock/tls'),
          },
        },
      };
  3. If you encounter a crypto issue for iOS (e.g. error "crypto.getRandomValues() not supported") you should install crypto-browserify and stream-browserify, then add the following lines to your metro.config.js file.

      const config = {
        resolver: {
          extraNodeModules: {
            crypto: require.resolve("crypto-browserify"),
            stream: require.resolve("stream-browserify"),
          },
        },
      };
  4. Add the following import on top of your entry point file

     import 'node-libs-react-native/globals';
     import 'react-native-get-random-values';
     import 'react-native-url-polyfill/auto';
     import '@azure/core-asynciterator-polyfill';

SDK Methods

Initialization

It handles the initialization of ChatSDK internal data.

import OmnichannelChatSDK from '@microsoft/omnichannel-chat-sdk';

const omnichannelConfig = {
    orgUrl: "",
    orgId: "",
    widgetId: ""
};

const chatSDKConfig = { // Optional
    dataMasking: {
        disable: false,
        maskingCharacter: '#'
    }
};

const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);

const optionalParams = {
    getLiveChatConfigOptionalParams: {
        sendCacheHeaders: false,// Whether to send Cache-Control HTTP header to GetChatConfig call
        useSequentialLoad: false // Whether to use sequential load for chat config, if not present, by default uses parallel load for faster initialization

    }
};


// For the case when the widget doesnt have enabled support for attachments, Upload/download operations wont be supported
await chatSDK.initialize(optionalParams);

Passing cpsBotId on initialization

cpsBotId in UUID format, when present will use v4 for GetchatToken. (Limited to enabled orgs) establishing the connection with Copilot Bot specified.

Scenarios

  • if bot id is present and valid, SDK will use V4 for GetchatToken establishing the connection with the dessired Copilot Bot.
  • if bot Id is not present, flow will continue using V2 for GetchatToken
  • if bot Id is not in valid format, expect a 400 HTTP Response Error Code
  • if bot Id is not enabled for the workstream, expect 403 HTTP Response Error Code

import OmnichannelChatSDK from '@microsoft/omnichannel-chat-sdk';

const omnichannelConfig = {
    orgUrl: "",
    orgId: "",
    widgetId: "",
    cpsBotId: ""
};

const chatSDKConfig = { // Optional
    dataMasking: {
        disable: false,
        maskingCharacter: '#'
    }
};

const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);

const optionalParams = {
    getLiveChatConfigOptionalParams: {
        sendCacheHeaders: false // Whether to send Cache-Control HTTP header to GetChatConfig call
    }
};

await chatSDK.initialize(optionalParams);

Start Chat

It starts an Omnichannel conversation.

const customContext = {
    'contextKey1': {'value': 'contextValue1', 'isDisplayable': true},
    'contextKey2': {'value': 12.34, 'isDisplayable': false},
    'contextKey3': {'value': true}
};

const optionalParams = {
    preChatResponse: '', // PreChatSurvey response
    liveChatContext: {}, // EXISTING chat context data
    customContext, // Custom Context
    sendDefaultInitContext: true // Send default init context ⚠️ Web only
};

await chatSDK.startChat(optionalParams);

End Chat

It ends the current Omnichannel conversation.

await chatSDK.endChat();

Get Pre-Chat Survey

It gets the Pre-Chat Survey from Live Chat Config. Pre-Chat Survey is in Adaptive Card format.

Option 1

const preChatSurvey = await getPreChatSurvey(); // Adaptive Cards JSON payload data

Option 2

const parseToJSON = false;
const preChatSurvey = await getPreChatSurvey(parseToJSON); // Adaptive Cards payload data as string

Get Live Chat Config

It fetches the Live Chat Config.

const liveChatConfig = await chatSDK.getLiveChatConfig();

Get Current Live Chat Context

It gets the current live chat context information to be used to reconnect to the same conversation.

const liveChatContext = await chatSDK.getCurrentLiveChatContext();

Get Data Masking Rules

It gets the active data masking rules from Live Chat Config. Returned type is defined as :


type MaskingRule = {
 id: string;
 regex: string;
}

type MaskingRules = {
 rules: MaskingRule[];
}
const dataMaskingRules : MaskingRules = await chatSDK.getDataMaskingRules();

Get Chat Reconnect Context

It gets the current reconnectable chat context information to connect to a previous existing chat session.

Reconnection options is required. See documentation

const optionalParams = {
    reconnectId: '', // reconnect Id
};

const chatReconnectContext = await chatSDK.getChatReconnectContext(optionalParams);

Get Conversation Details

It gets the details of the current conversation such as its state & when the agent joined the conversation.

const optionalParams = {
    liveChatContext: {}, // EXISTING chat context data
};

const conversationDetails = await chatSDK.getConversationDetails(optionalParams);

Get chat Token

It gets the chat token used to initiate a chat with Omnichannel messaging client.

const chatToken = await chatSDK.getChatToken();

Get Calling Token

It gets the calling token used to initiate a Voice & Video Call.

const callingToken = await chatSDK.getCallingToken();

Get Messages

It gets all the messages of the current conversation.

const messages = await chatSDK.getMessages();

Send Messages

It sends a message to Omnichannel.

import {DeliveryMode, MessageContentType, MessageType, PersonType} from '@microsoft/omnichannel-chat-sdk';

...

const message = "Sample message from customer";
const messageToSend = {
    content: message
};

await chatSDK.sendMessage(messageToSend);

On New Message

It subscribes to new incoming messages of the current conversation such as system messages, client messages, agent messages, adaptive cards and attachments.

const optionalParams = {
    rehydrate: true, // Rehydrate all previous messages of existing conversation (false by default)
}

chatSDK.onNewMessage((message) => {
    console.log(`[NewMessage] ${message.content}`);
    console.log(message);
}, optionalParams);

On Typing Event

It subscribes to an agent typing event.

chatSDK.onTypingEvent(() => {
    console.log("Agent is typing...");
})

On Agent End Session

It subscribes to an agent ending the session of the conversation.

chatSDK.onAgentEndSession(() => {
    console.log("Session ended!");
});

Send Typing Event

It sends a customer typing event.

await chatSDK.sendTypingEvent();

Email Live Chat Transcript

It sends an email of the live chat transcript.

const body = {
    emailAddress: 'contoso@microsoft.com',
    attachmentMessage: 'Attachment Message'
};
await chatSDK.emailLiveChatTranscript(body);

Get Live Chat Transcript

It fetches the current conversation transcript data in JSON.

const optionalParams = {
    liveChatContext: {}, // EXISTING chat context data
};

await chatSDK.getLiveChatTranscript(optionalParams);

Upload File Attachment

It sends a file attachment to the current conversation.

const fileInfo = {
    name: '',
    type: '',
    size: '',
    data: ''
};
await chatSDK.uploadFileAttachment(fileInfo);

Download File Attachment

It downloads the file attachment of the incoming message as a Blob response.

const blobResponse = await chatsdk.downloadFileAttachment(message.fileMetadata);

...

// React Native implementation
const fileReaderInstance = new FileReader();
fileReaderInstance.readAsDataURL(blobResponse);
fileReaderInstance.onload = () => {
    const base64data = fileReaderInstance.result;
    return <Image source={{uri: base64data}}/>
}

Create Chat Adapter

:warning: Currently supported on web only

It creates a chat adapter to use with BotFramework-WebChat.

const chatAdapter = await chatSDK.createChatAdapter();

Get Voice & Video Calling

:warning: Currently supported on web only

:warning: Please ensure voice & video call is stopped before leveraging endChat SDK method

It fetches the SDK for Escalation to Voice & Video.

try {
    const VoiceVideoCallingSDK = await chatSDK.getVoiceVideoCalling();
    console.log("VoiceVideoCalling loaded");
} catch (e) {
    console.log(`Failed to load VoiceVideoCalling: ${e}`);

    if (e.message === 'UnsupportedPlatform') {
        // Voice Video Calling feature is not supported on this platform
    }

    if (e.message === 'FeatureDisabled') {
        // Voice Video Calling feature is disabled on admin side
    }
}

Get Post Chat Survey Context

It gets the participant type that should be used for the survey and both the default and bot survey details.

const postChatSurveyContext = await chatSDK.getPostChatSurveyContext();

Get Agent Availability

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.

const agentAvailability = await chatSDK.getAgentAvailability();

Common Scenarios

Pre-Chat Survey

See https://docs.microsoft.com/en-us/dynamics365/customer-service/configure-pre-chat-survey?tabs=customerserviceadmincenter on how to set up pre-conversation surveys

    import * as AdaptiveCards, { Action } from "adaptivecards";

    ...

    const preChatSurvey = await chatSDK.getPreChatSurvey();

    ...

    // Web implementation
    const renderPreChatSurvey = () => {
        const adaptiveCard = new AdaptiveCards.AdaptiveCard();
        adaptiveCard.parse(preChatSurvey); // Parses Adaptive Card JSON data
        adaptiveCard.onExecuteAction = async (action: Action) => { // Adaptive Card event handler
            const preChatResponse = (action as any).data;
            const optionalParams: any = {};
            if (preChatResponse) {
                optionalParams.preChatResponse = preChatResponse;
            }
            await chatSDK.startChat(optionalParams);
        }

        const renderedCard = adaptiveCard.render(); // Renders as HTML element
        return <div ref={(n) => { // Returns React element
            n && n.firstChild && n.removeChild(n.firstChild); // Removes duplicates fix
            renderedCard && n && n.appendChild(renderedCard);
        }} />
    }

Post-Chat Survey

See https://docs.microsoft.com/en-us/dynamics365/customer-service/configure-post-conversation-survey?tabs=customerserviceadmincenter on how to set up post-conversation surveys

NOTE : It should be called ONLY when the chat contains a post-survey as part of their configuration, otherwise it will throw an error.

chatSDK.getPostChatSurveyContext() needs to be called before chatSDK.endChat() is called.

// 1. Start chat
await chatSDK.startChat();

// 2. Save post chat survey context before ending chat
try {
    const context = await chatSDK.getPostChatSurveyContext();
    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 the admin side.
        // formsProLocale is the default language you have set on the CustomerVoice portal. You can override this url parameter with any locale that CustomerVoice supports.
        // If "&lang=" is not set on the url, the locale will be English.
        const link = context.participantType === "Bot" ? context.botSurveyInviteLink : context.surveyInviteLink;
        const locale = context.participantType === "Bot" ? context.botFormsProLocale : context.formsProLocale;
        const linkToSend = link + "&lang=" + locale;
        // This link is accessible and will redirect to the survey page. Use it as you see fit.
    }
} catch (ex) {
    // If the post chat should not be shown for any reason (e.g. post chat is not enabled), promise will be rejected.
}

// 3. End chat
await chatSDK.endChat();

// 4. Display Post Chat

Reconnect to existing Chat

await chatSDK.startChat(); // Starts NEW chat

const liveChatContext = await chatSDK.getCurrentLiveChatContext(); // Gets chat context

cache.saveChatContext(liveChatContext); // Custom logic to save chat context to cache

...

// Page/component reloads, ALL previous states are GONE

...

const liveChatContext = cache.loadChatContext() // Custom logic to load chat context from cache

const optionalParams = {};
optionalParams.liveChatContext = liveChatContext;

await chatSDK.startChat(optionalParams); // Reconnects to EXISTING chat

...

const messages = await chatSDK.getMessages(); // Gets all messages from EXISTING chat
messages.reverse().forEach((message: any) => renderMessage(message)); // Logic to render all messages to UI

Authenticated Chat

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

const chatSDKConfig = {
    getAuthToken: async () => {
        const response = await fetch("http://contosohelp.com/token");
        if (response.ok) {
            return await response.text();
        }
        else {
            return null
        }
    }
}

const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
await chatSDK.initialize();

// from this point, this acts like a regular chat widget

Persistent Chat

See https://docs.microsoft.com/en-us/dynamics365/customer-service/persistent-chat on how to set up persistent chat

const chatSDKConfig = {
    persistentChat: {
        disable: false,
        tokenUpdateTime: 21600000
    },
    getAuthToken: async () => {
        const response = await fetch("http://contosohelp.com/token");
        if (response.ok) {
            return await response.text();
        }
        else {
            return null
        }
    }
}

const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
await chatSDK.initialize();

// from this point, this acts like a persistent chat

Chat Reconnect with Authenticated User

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

const chatSDKConfig = {
    chatReconnect: {
        disable: false,
    },
    getAuthToken: async () => {
        const response = await fetch("http://contosohelp.com/token");
        if (response.ok) {
            return await response.text();
        }
        else {
            return null
        }
    }
}

const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
await chatSDK.initialize();

...

const chatReconnectContext = await chatSDK.getChatReconnectContext();

if (chatReconnectContext.reconnectId) {
    // Add UX with options to reconnect to previous existing chat or start new chat
}

// Reconnect chat option
const optionalParams = {};
optionalParams.reconnectId = chatReconnectContext.reconnectId;
chatSDK.startChat(optionalParams);

// Start new chat option
chatSDK.startChat();

Chat Reconnect with Unauthenticated User

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

const chatSDKConfig = {
    chatReconnect: {
        disable: false,
    },
}

const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
await chatSDK.initialize();

....

const optionalParams: any = {};

// Retrieve reconnect id from the URL
const urlParams = new URLSearchParams(window.location.search);
const reconnectId = urlParams.get('oc.reconnectid');

const params = {
    reconnectId
};

// Validate reconnect id
const chatReconnectContext = await chatSDK.getChatReconnectContext(params);

// If the reconnect id is invalid or expired, redirect URL if there is any URL set in the configuration
if (chatReconnectContext.redirectURL) {
    window.location.replace(chatReconnectContext.redirectURL);
}

// Valid reconnect id, reconnect to previous chat
if (chatReconnectContext.reconnectId) {
    await chatSDK.startChat({
        reconnectId: chatReconnectContext.reconnectId
    });
} else {  // Reconnect id from URL is not valid, start new chat session
    await chatSDK.startChat();
}

Operating Hours

See https://docs.microsoft.com/en-us/dynamics365/customer-service/create-operating-hours?tabs=customerserviceadmincenter on how to set up operating hours

const chatConfig = await chatSDK.getLiveChatConfig();
const {LiveWSAndLiveChatEngJoin: liveWSAndLiveChatEngJoin} = liveChatConfig;
const {OutOfOperatingHours: outOfOperatingHours} = liveWSAndLiveChatEngJoin;

if (outOfOperatingHours === "True") {
    // Handles UX on Out of Operating Hours
} else {
    await chatSDK.startChat();
    // Renders Custom Chat Widget
}

Best Practices for Chat Session Management: Handling Disconnections and Network Instability

When users switch away from a browser tab or move an browser app to the background, it's important to check if the chat session is still active before allowing message sending when user resumes. This applies to both mobile and desktop environments, as sessions can expire or disconnect when not actively used

// 1. Register a listener for visbilitychange event
window.addEventListener("visibilitychange", async () => {
// 2. verify if the browser is in the foreground by checking the document.hidden property
    if (!document.hidden)  {
//3. Check conversation state by making a call to getConversationDetails
        const optionalParams = {
            liveChatContext: {}, // EXISTING chat context data
        };
        const conversationDetails = await chatSDK.getConversationDetails(optionalParams);
         if (conversationDetails?.state === "WrapUp" || conversationDetails?.state === "Closed") {
//4. Show disconnect notification to customer and disable the input box so that user cannot send a message            
         }

    }
});



window.addEventListener('online', async () => {
  // Re-establish chat connection
   const optionalParams = {
        liveChatContext: {}, // EXISTING chat context data
    };
    const conversationDetails = await chatSDK.getConversationDetails(optionalParams);
    if (conversationDetails?.state === "WrapUp" || conversationDetails?.state === "Closed") {

    }
});

window.addEventListener('offline', () => {
  // Inform user of connectivity issues
});

Using BotFramework-WebChat

:warning: Currently supported on web only

Minimum Requirement Checklist

  1. <input disabled="" type="checkbox"> Initialize ChatSDK
  2. <input disabled="" type="checkbox"> Start new conversation
  3. <input disabled="" type="checkbox"> Create Chat Adapter
  4. <input disabled="" type="checkbox"> Create WebChat store with default middlewares
    1. <input disabled="" type="checkbox"> Send Default Channel Message Tags using Store Middleware (See here) ❗ Required
  5. <input disabled="" type="checkbox"> Render WebChat
import OmnichannelChatSDK from '@microsoft/omnichannel-chat-sdk';
import ReactWebChat, {createStore} from 'botframework-webchat';

// 1. ChatSDK Initialization
const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig);
await chatSDK.initialize();

// 2. Start new conversation
await chatSDK.startChat();

// 3. Create chat adapter
const chatAdapter = await chatSDK.createChatAdapter();

// 4. Create WebChat store with middlewares
const store = createStore(
    {}, // initial state
    sendDefaultMessagingTagsMiddleware // ❗ Required
);

// 5. Render WebChat
<ReactWebChat
    store={store}
    userID="teamsvisitor"
    directLine={chatAdapter}
    sendTypingIndicator={true}
/>

Escalation to Voice & Video

:warning: Currently supported on web only

See https://docs.microsoft.com/en-us/dynamics365/customer-service/call-options-visual-engagement on how to set up calling options

import OmnichannelChatSDK from '@microsoft/omnichannel-chat-sdk';

...

const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
await chatSDK.initialize();

let VoiceVideoCallingSDK;
try {
    VoiceVideoCallingSDK = await chatSDK.getVoiceVideoCalling();
    console.log("VoiceVideoCalling loaded");
} catch (e) {
    console.log(`Failed to load VoiceVideoCalling: ${e}`);

    if (e.message === 'UnsupportedPlatform') {
        // Voice Video Calling feature is not supported on this platform
    }

    if (e.message === 'FeatureDisabled') {
        // Voice Video Calling feature is disabled on admin side
    }
}

await chatSDK.startChat();

const chatToken: any = await chatSDK.getChatToken();

// Initialize only if VoiceVideoCallingSDK is defined
if (VoiceVideoCallingSDK) {
    try {
        await VoiceVideoCallingSDK.initialize({
            chatToken,
            selfVideoHTMLElementId: 'selfVideo', // HTML element id where video stream of the agent will be rendered
            remoteVideoHTMLElementId: 'remoteVideo', // HTML element id where video stream of the customer will be rendered
            OCClient: chatSDK.OCClient
        });
    } catch (e) {
        console.error("Failed to initialize VoiceVideoCalling!");
    }

    // Triggered when there's an incoming call
    VoiceVideoCallingSDK.onCallAdded(() => {
        ...
    });

    // Triggered when local video stream is available (e.g.: Local video added succesfully in selfVideoHTMLElement)
    VoiceVideoCallingSDK.onLocalVideoStreamAdded(() => {
        ...
    });

    // Triggered when local video stream is unavailable (e.g.: Customer turning off local video)
    VoiceVideoCallingSDK.onLocalVideoStreamRemoved(() => {
        ...
    });

    // Triggered when remote video stream is available (e.g.: Remote video added succesfully in remoteVideoHTMLElement)
    VoiceVideoCallingSDK.onRemoteVideoStreamAdded(() => {
        ...
    });

    // Triggered when remote video stream is unavailable (e.g.: Agent turning off remote video)
    VoiceVideoCallingSDK.onRemoteVideoStreamRemoved(() => {
        ...
    });

    // Triggered when current call has ended or disconnected regardless the party
    VoiceVideoCalling.onCallDisconnected(() => {
        ...
    });

    // Check if microphone is muted
    const isMicrophoneMuted = VoiceVideoCallingSDK.isMicrophoneMuted();

    // Check if remote video is available
    const isRemoteVideoEnabled = VoiceVideoCallingSDK.isRemoteVideoEnabled();

    // Check if local video is available
    const isLocalVideoEnabled = VoiceVideoCallingSDK.isLocalVideoEnabled();

    // Accepts incoming call
    const acceptCallConfig = {
        withVideo: true // Accept call with/without video stream
    };
    await VoiceVideoCallingSDK.acceptCall(acceptCallConfig);

    // Rejects incoming call
    await VoiceVideoCallingSDK.rejectCall();

    // Ends/Stops current call
    await VoiceVideoCallingSDK.stopCall();

    // Mute/Unmute current call
    await VoiceVideoCallingSDK.toggleMute()

    // Display/Hide local video of current call
    await VoiceVideoCallingSDK.toggleLocalVideo()

    // Clean up VoiceVideoCallingSDK (e.g.: Usually called when customer ends chat session)
    VoiceVideoCallingSDK.close();
}

Feature Comparisons

Web

| | Custom Control | WebChat Control | | --- | --- | --- | | Features | | | | Chat Widget UI | Not provided | Basic chat client provided | | Data Masking | Embedded | Requires Data Masking Middleware implementation | | Send Typing indicator | Embedded | Requires sendTypingIndicator flag set to true | | PreChat Survey | Requires Adaptive Cards renderer | Requires Adaptive Cards renderer| | Display Attachments | Requires implementation | Basic interface provided & Customizable | | Incoming messages handling | IC3 protocol message data | DirectLine activity data |

React Native

| | Custom Control | Gifted Chat Control | WebChat Control | | --- | --- | --- | --- | | Features | | | Currently not supported | | Chat Widget UI | Not provided | Basic chat client provided | X | | Data Masking | Embedded | Embedded | X | | Send Typing indicator | Embedded | Requires Implementation | X | | PreChat Survey | Requires Adaptive Cards renderer | Requires Adaptive Cards renderer | X | | Display Attachments | Requires implementation| Embedded | X | | Incoming messages handling |IC3 protocol message data | IC3 protocol message data | X |

Telemetry

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.

Some of the data being collected are the following:

Field Sample
Organization Id e00e67ee-a60e-4b49-b28c-9d279bf42547
Organization Url org60082947.crm.oc.crmlivetie.com
Widget Id 1893e4ae-2859-4ac4-9cf5-97cffbb9c01b
Browser Name Edge
Os Name Windows
Anonymized IP Address (last octet redacted) 19.207.000.000

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.

const omnichannelConfig = {
    orgUrl: "",
    orgId: "",
    widgetId: ""
};

const chatSDKConfig = {
    telemetry: {
        disable: true // Disable telemetry
    }
};

const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
await chatSDK.initialize();

Contributing

This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.

When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.

changelog

Changelog

All notable changes to this project will be documented in this file.

[Unreleased]

[1.11.6] - 2025-08-08

Fixed

  • Implement mutex pattern to prevent race conditions between startChat() and endChat() operations that could lead to state corruption

Changed

  • uptake amsclient "@microsoft/omnichannel-amsclient": "^0.1.11"

[1.11.5] - 2025-07-31

Fixed

  • Fix Error object serialization in ACSAdapterLogger.failScenario() to prevent JSON.stringify errors when ExceptionDetails contains Error instances
  • Validate request payload passed to OCClient.getSurveyInviteLink in ChatSDK.getPostChatSurveyContext()

Changed

  • Add customEvent property to OmnichannelMessage to support custom event metadata propagation to mobile SDKs (Android/iOS).

[1.11.4] 2025-07-17

Changed

  • When a exception is detected during AMS initialization, the chat will log the error and continue with the chat initialization.

[1.11.3] 2025-07-14

Fixed

  • Fix conversation cleanup when MessagingClientConversationJoinFailure occurs to prevent orphaned conversations

Changed

  • Clean up ChatSDK.sendTypingEvent() unused code path
  • Add HttpRequestResponseTime property to OCSDKLogData and OCSDKContract Interfaces for HTTP request duration tracking
  • Uptake @microsoft/ocsdk@0.5.18
  • Update regionBasedSupportedUrls to include GCC

[1.11.2] - 2025-06-24

Changed

[1.11.1] - 2025-06-05

Changed

[1.11.0] - 2025-05-27

Fixed

  • added failure exception details to initialize parallel
  • Uptake new oc sdk with changes to requestId
  • Added Finally to solve cleanup issues while closing chat
  • Update new OC sdk for correlation id implementation

Added

  • Mapped id to OriginalMessage ID for backward compatibility once the bridging is removed
  • Added additions details to endChat ExceptionDetails
  • Splited sessionInit promize to its own to avoid ACS initialize

Changed

[1.10.19] - 2025-05-02

Added

  • Turned on new conversation api by default
  • Added additional details from underlying component for sendMessage failure
  • Added "role" attribute for received messages

[1.10.18] 2025-04-09

Added

[1.10.17] 2025-04-07

Added

  • Load AMS based on config.

Fixed

  • Fix for methods receiving exceptionDetails , but not logging it in telemetry
  • Fix to prevent double load of AMS
  • Fix to prevent startchat to finish before AMS client loads. (latency detected, future work to be part of AMS client enhancements)

[1.10.16] - 2025-03-27

Added

  • Added exception details for telemetry for SendMessage
  • Expose OriginalMessageId to ChatSDK.onNewMessage() to handle message ordering
  • Update ChatSDK.sendMessage() to return OmnichannelMessage

Changed

[1.10.15] - 2025-03-11

Security

Added

  • Added support for createConversation api which eleminates need for 2 api's when starting a conversation.
  • Adding telemetry around receive message mechanisms, Rest, Websocket and Polling

Fixed

  • Additional types for stored timer Id.

[1.10.14] - 2025-03-06

Changed

  • Updated getLivechatTranscript livechatcontect check for persistent chat

Added

  • Add check for getConversation details before call onAgentEndSession call back since participant removed is not reliable

[1.10.13] - 2025-03-04

Added

  • Add disablePolling flag for onNewMessage to stop polling

Changed

Fixed

  • Update ACSAdapterVersion to reflect the correct version

[1.10.12] - 2025-02-21

Added

  • Enabling LongPolling to continue after websocket is set, to prevent messages lost. Polling will stop when conversation ends.
  • Added stopPolling method to stop the long polling when ending the chat.

[1.10.11] - 2025-02-20

Added

  • Reduce polling interval with exponential backoff

[1.10.10] - 2025-02-18

Changed

[1.10.9] - 2025-02-06

Changed

[1.10.8] - 2025-02-05

Fixed

  • Fix ChatSDK.onNewMessages() calling createOmnichannelMessages() twice during polling

Changed

[1.10.7] - 2025-01-30

Added

  • Added push notification properties to session init optional params

[1.10.6] - 2025-01-28

Added

  • Fix for ACS client preventing new messages from being populated in the new message callback.
  • Updated chat adapter dependecy ,also created new logic for PI data scrubbing

[1.10.5] - 2025-16-01

Added

  • Update of missing telemetry events for exposed API's
  • Adding exception details for telemetry for Email Transcript
  • Adding exception details for telemetry for GetMessages / SendMessages
  • Adding validation to exposed API's to require validations before to be executed.

Changed

[1.10.4] - 2024-12-19

Fixed

  • types not included in external exports.

[1.10.3] - 2024-12-19

Fixed

  • Missing type definitions for public API's responses, removing any as response type
  • Defining explicit response types for void functions.
  • Defining a type for MaskingRules
  • Restructure for ChatConfig initialization and build of entities around it.

[1.10.2] - 2024-12-06

Added

  • Adding optional params for end chat to allow decide internally when to call close session backend.

Fixed

  • Added console log when the given widget id is no longer found in the system

Changed

[1.10.1] - 2024-11-11

Fixed

  • Add requestId to OCClient.getReconnectableChats() parameters
  • Load ACS Chat adapter as npm dependency, instead of download it from unpkg host.

[1.10.0] - 2024-10-31

Changed

[1.9.10] - 2024-10-25

Changed

[1.9.9] - 2024-10-21

Fixed

  • Fix CoreServices orgUrl conversion for crm9 orgs

[1.9.8] - 2024-10-18

Changed

  • Updating dev libraries and unit tests

[1.9.7] - 2024-10-16

Changed

  • Added to new versioned path to callingbundle.js

[1.9.6] - 2024-09-19

Added

  • Adding mechanism to initialize SDK using parallel threads for a faster load, still supporting sequential load

Changed

[1.9.5] - 2024-08-30

Security

[1.9.3] - 2024-07-12

Added

  • Add crm9 as part of CoreServicesGeoNamesMapping

Changed

  • Log error object on failures on sending message and send typing
  • Update retrieveCollectorUri() to detect GCCDomainPatterns to return GCCCollectorUri

[1.9.2] - 2024-06-25

Fixed

  • Remove internal overrides of the original message contracts to add content property with Object.assign() causing side effects on ChatAdapter

[1.9.1] - 2024-06-20

Changed

[1.9.0] - 2024-05-22

Added

  • Enable the ability to use CoreServices orgUrl dynamically at runtime

Changed

[1.8.3] - 2024-05-15

Added

  • Add RequestHeaders telemetry base property to OCSDKContract
  • Add ability to send ocUserAgent

Changed

[1.8.2] - 2024-05-07

Fixed

  • Fix path for util function uuidv4 that was causing conflicts with pipeline

[1.8.1] - 2024-04-24

Added

  • Adding new externalRuntimeId, allows to pass external runtimeId to ChatSDK and keep in sync sessions for telemetry.
  • Add ability to use CoreServices orgUrl dynamically at runtime

[1.8.0] - 2024-03-29

Changed

  • Updated OCClient.getSurveyInviteLink request payload to support Copilot Survey

[1.7.2] - 2024-03-20

Fixed

  • Remove override block for follow-redirect, which was causing conflicts with ACS libs in LCW

[1.7.1] - 2024-03-18

Changed

  • Fix ChatSDK.getPostConversationContext() to reject promise when conversation is not found

[1.7.0] - 2024-03-07

Added

  • Add ability to use ChatSDK.emailLiveChatTranscript() to email live chat transcript from liveChatContext
  • Handling the lifecycle of sessionId if it exists

Changed

  • Throw exception when ChatSDK.startChat() fails with ChatSDKConfig.getAuthToken() failures
  • Uptake @microsoft/ocsdk@0.4.3

[1.6.3] - 2024-01-30

Changed

  • Reduce number of config calls on loading Escalation to Voice & Video library by retrieving the config from runtime cache

[1.6.2] - 2023-12-12

Fixed

  • Add supportedImagesMimeTypes to support MIME types image/heic & image/webp as images

[1.6.1] - 2023-12-07

Added

  • Exported ChatSDKErrorName and ChatSDKError for downstream component to use

Fixed

  • Subscribe to chatMessageEdited events within onNewMessage() for queue position message updates

Changed

[1.6.0] - 2023-12-04

Changed

  • Added "httpResponseStatusCode" attribute in the error object thrown

[1.5.7] - 2023-11-20

Changed

[1.5.6] - 2023-11-13

Added

  • Add RequestPayload, RequestPath, RequestMethod, ResponseStatusCode telemetry base property to OCSDKContract
  • Update Jest configuration and tests to support new libraries

Security

Changed

  • Use parseLowerCaseString() on chat config properties to protect text case change

[1.5.5] - 2023-10-31

Added

  • Add ability to pass custom ariaCollectorUri

Fixed

  • Add missing PACS URL for EUDomainNames
  • Fixed an issue where startChat failed due to optionalParam being null

[1.5.4] - 2023-10-20

Fixed

  • Fix AriaTelemetry._configuration not being passed to AriaTelemetry._logger

[1.5.3] - 2023-10-18

Fixed

  • Fix ChatSDK.emailLiveChatTranscript() calling OCClient.emailTranscript() without waiting until its completion
  • Fix EU orgs telemetry to flow to the proper EU location

[1.5.2] - 2023-10-14

Changed

  • Disable tokenRefresher temporarily

[1.5.1] - 2023-10-11

Fixed

  • Modify getChatReconnectContext to return redirection URL when reconnection ID is not longer Valid for Auth Chats.

[1.5.0] - 2023-09-29

Added

  • Add Attachment File Scan to ChatSDK.createChatAdapter()

[1.4.7] - 2023-09-13

Changed

  • Supporting getAgentAvailable SDK method for unauthenticated chat widget

[1.4.6] - 2023-08-15

Fixed

  • Fix tokenRefresher to update chatToken properly on expiry through reinitialization of AMSClient

[1.4.5] - 2023-08-02

Changed

  • Upgraded ACSAdapter to version beta.20

[1.4.4] - 2023-07-19

Added

  • Add tokenRefresher mechanism to retrieve chat token on expiry

Changed

  • Add ocSDKConfiguration to reduce chatToken retries to 2
  • Uptake @microsoft/ocsdk@0.4.0
  • Remove redundant call to create of participantsMapping

Fixed

  • Set enableSenderDisplayNameInTypingNotification to true to include display name on sending typing notification
  • Add async to ChatSDK.getLiveChatTranscript() internal call

[1.4.3] - 2023-06-15

Fixed

  • [Perf] Make sessionInit, AcsClientInit/Ic3ClientInit and AmsClientInit calls in parallel

[1.4.2] - 2023-05-19

Fixed

  • Fixed null check on startChat failure

[1.4.1] - 2023-05-05

Fixed

  • Skipped empty string or null context variables (parity with v1)

[1.4.0] - 2023-05-02

Added

  • Add ability to use ChatSDK.getLiveChatTranscript() to fetch live chat transcript from liveChatContext
  • Add ability to use ChatSDK.getConversationDetails() to fetch conversation details from liveChatContext
  • Add AuthContactIdNotFoundFailure to ExceptionThrower

Changed

  • Update ChatSDKErrors to include standard ChatSDK errors to be more predictable

[1.3.0] - 2023-04-05

Added

  • Add ability to use ChatSDK.createChatAdapter() for DirectLine protocol
  • Add CreateACSAdapter telemetry event
  • Improve ChatSDK.createChatAdapter() with retries using exponential backoff & additional details on failures
  • Add GetAgentAvailability SDK method for auth chat
  • Pass logger to AMSClient
  • Add portalContactId in StartChatOptionalParams and GetAgentAvailabilityOptionalParams
  • Added exception on initialization failure
  • Upgraded ACSAdapter to version beta.17
  • Added botSurveyInviteLink and botFormsProLocale the getPostChatSurveyContext() response

Fixed

  • Fix ChatAdapterOptionalParams.ACSAdapter.options.egressMiddleware being used as ingressMiddleware
  • Fix ChatSDK.onTypingEvent() being triggered on current user typing
  • Update ChatSDK.liveChatVersion to be V2 by default

Changed

[1.2.0] - 2022-11-11

Added

  • Add sendDefaultInitContext optional parameter to ChatSDK.startChat() to automatically populate browser, device, originurl & os as default init context on web
  • Add sendCacheHeaders as optional paramater to ChatSDK.initialize() and ChatSDK.getLiveChatConfig()
  • Add validateAuthChatRecord call on ChatSDK.startChat() with liveChatContext for all authenticated chat scenarios
  • Pass ChatClient during ACSAdapter initialization
  • Pass multiClient to AMSClient on initialization to support ChatSDK multi-client

Fixed

  • Prevent AMSFileManager.getFileIds() & AMSFileManager.getFileMetadata() to be triggered on all activities with null checks
  • Add LiveChatVersion check on ChatSDK.updateChatToken()
  • Use amsreferences property instead of amsReferences by default
  • Fix attachment download to use MIME types instead of file extensions
  • Remove fileMetadata property on messages not containing any attachment

Changed

[1.1.0] - 2022-04-15

Added

  • Add getPostChatSurveyContext API method
  • Add GetPostChatSurveyContext telemetry event
  • Add widgetId & clientMessageId as metadata on sending message
  • Update ChatConfig interface with LiveChatVersion, allowedFileExtensions & maxUploadFileSize properties
  • Add ability to automatically detect locale from chat config
  • Add runtimeId attribute in OmnichannelChatSDK & ChatSDKRuntimeId field in telemetry
  • Add ability to automatically pass locale from chat config on calling ChatSDK.emailLiveChatTranscript()
  • Bubble up WidgetUseOutsideOperatingHour exception
  • Add acs_webchat-chat-adapter middleware to add default channelData.tags & channelData.metadata
  • Update ChatConfig interface with msdyn_enablemarkdown property
  • Throw exception on ChatSDK.getVoiceVideoCalling() if feature is disabled or platform is not supported
  • Add participantType & canRenderPostChat as response of getConversationDetails() API
  • Add support for separate bot post chat survey feature
  • Pass logger to acs_webchat-chat-adapter

Fixed

  • Add acs_webchat-chat-adapter middlewares to format channelData.tags
  • Skip session init call on existing conversation
  • Fix chat reconnect not ending the conversation on calling ChatSDK.endChat()
  • Fix on messaging client not sending heartbeat on new conversations subsequent to the first conversation
  • Fix ChatSDK.getConversationDetails() not passing authenticatedUserToken
  • Fix IC3Client.dispose() called when IC3Client is undefined

Changed

[1.0.0] - 2021-10-08

Added

  • Add GetAuthToken & GetPreChatSurvey telemetry events
  • Add Domain telemetry base property
  • Add GetCurrentLiveChatContext, GetMessages, SendMessages, OnNewMessage & OnTypingEvent telemetry events
  • Live Chat V2 Support
  • Add PlatformDetails telemetry event

Changed

Fixed

  • onNewMessage with rehydrate flag set to true crashing when getMessages returns undefined
  • Fix AriaTelemetry unable to read property logEvent of undefined on React Native
  • Fix Escalation to Voice & Video library not being imported properly

[0.3.0] - 2021-09-03

Added

  • Persistent Chat Support
  • Chat Reconnect Support
  • Operating Hours Documentation

Changed

Fixed

  • msdyn_enablechatreconnect not being parsed properly
  • Fix unable to start multiple conversations with same instance due to chat client being disposed
  • Pass logger to adapter

[0.2.0] - 2021-04-30

Added

  • React Native sample app using Omnichannel Chat SDK with react-native-gifted-chat
  • Escalation to Voice & Video support (Web Only)
  • React sample app using Omnichannel Chat SDK with BotFramework-WebChat
  • Expose sessiontInit's initContext on startChat's optional paramaters
  • Add ability to use custom ic3Config & chatAdapterConfig
  • Add telemetry
  • Add rehydrate flag for onNewMessage to rehydrate all messages of existing conversation
  • Add getConversationDetails
  • Add ability to pass custom ariaTelemetryKey

Changed

Fixed

  • onAgentEndSession triggered on accept voice & video call
  • Fix multiple instances of IC3Client initialized
  • uploadFileAttachment failing on Web

Security

  • Fix eslint errors

[0.1.0] - 2020-10-26

Added

  • Initial release of Omnichannel Chat SDK v0.1.0