Motivation behind this
Building Einstein Bot is nothing new and there are plenty of blogs and documentations are available on searching. Recently I got a use case from a Customer who wants on-demand transfer to agent as well as want to see end-to-end functionality.
As no such blogs or documentations exist on this specific requirement which drives me to setup and explore a quick proof of concept.
Let's start with basics first.
Capabilities of Einstein Bot
It is used to increase deflection and reduce call handling time.
- Automatically resolves customer issues - through providing answers using NLP and connected CRM data.
- Collect and qualify customer information - seamlessly handover real agent
- Easily connect to a business process - initiate & complete actions on behalf
- Quickly train, deploy and learn - Bot Builder is available to build it quick.
Product Requirements of Einstein Bot
- Enable Lightning Experience
- Service Cloud License or Chat or Messaging License
- Enable Chat
- Publish a Salesforce Community
- Create and deploy chat button to Community
- Provide chat at Service console
Use Case
Business wants to see the capabilities of Einstein Bot and wants to transfer to agent upon clicking on a button on Bot Header.
Solution Approach
Lets first build the bot what can be done in a quicker way and mostly through configuration and later we will proceed with customization as per need.
Build a Bot from Pre-defined Template
Reach from Setup -> Service Cloud Einstein -> Einstein Bots -> New button
1. Select a bot from template
2. Personalize your bot
3. How your bot help customers
Here choose, Report an issue and Check status for an existing issue.
4. Finishing
Embedded Service Deployments
From Setup -> Search with "Embedded Service Deployments" and create a new deployment as follows.
Next screen, name it as Customer Service and choose Site Endpoint as "Default_Help_Center"
After creating, we will find this as below.
From this screen, we can configure chat settings, change the branding as per requirement.
Build the intent
From Einstein Bot configurations, build intent and utterances.
Finally activate the Bot.
Set up Chat
1. From Service Cloud Setup Home, Recommended Setup Section, click on View All and Choose "Chat with Customers" menu
2. Create a chat queue and assign your user or other user in the queue.
3. Prioritize chat with other network.
Here I have mentioned Customer Service Queue with highest priority
Choose which mentioned as default.
6. Chat Type
Select as Service for this purpose.
7. Create support form
8. Code Snippet Generated
Keep this API Endpoint which will be needed for Community Setup.
Create Community
1. Digital Experiences -> All Sites -> Click on New button and choose Customer Service Template and follow guided process.
2. Builder --> Settings -> Security & Privacy
Choose Security Level as Relaxed CSP.
The chat settings URL to be added into trusted site
Overall, it will look like this.
3. Add Embedded Chat to Community
Go to your Customer Support page and add Embedded Service Chat Component to the page and define parameters as Chat Deployment as Customer Service.
Chat Agent Configuration
Define Chat Agent configuration as follows:
Up to this point no customizations required, but to match business requirements let's proceed for customization.
Customization of Einstein Bot
To meet above requirement, Setup LMS and BotChatHeader Component will be publisher and BotChatMessage component will be subscriber.
1. Setup Lightning Message Service
To start with, first create a message channel and push it to the org. the xml will be placed under force-app/main/default/messageChannels/ directory.
Here message channel name has given as Bot_EntityId and the file name will be Bot_EntityId.messageChannel-meta.xml
<?xml version="1.0" encoding="UTF-8" ?>
<LightningMessageChannel xmlns="http://soap.sforce.com/2006/04/metadata">
<masterLabel>BotEntityId</masterLabel>
<isExposed>true</isExposed>
<description>Message Channel to pass a entity Id</description>
<lightningMessageFields>
<fieldName>entityInfo</fieldName>
<description>This is information passed when Live Chat is clicked</description>
</lightningMessageFields>
</LightningMessageChannel>
2. Create Chat Header Component
BotChatHeader.html
Here beside the text, button to be displayed and clicking on that it will send the message.
<template>
<h2 aria-live="polite">
{text}
<template if:true={isLiveChatButtonDisplay}>
<button onclick={handleClick} aria-live="off">
<lightning-icon icon-name="standard:messaging_user"
alternative-text="Live Chat!"
class="slds-m-left_xx-small" title="Live Chat!">
</lightning-icon>
</button>
</template>
</h2>
<button onclick={minimize} aria-live="off">
<lightning-icon icon-name="utility:minimize_window"></lightning-icon>
</button>
<button onclick={close} aria-live="off">
<lightning-icon icon-name="utility:close"></lightning-icon>
</button>
</template>
BotChatHeader.js
Few notable points in this js file:
- Importing message channel to communicate via LMS.
// Import message service features required for publishing and the message channel
import { publish, MessageContext } from 'lightning/messageService';
import selectedEntity from '@salesforce/messageChannel/Bot_EntityId__c';
- Publishing a message "Representative please" which available as intent for Transferring an agent dialog and sending as payload in handleClick() event.
Entire js file as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70 | import { wire } from 'lwc';
// Import message service features required for publishing and the message channel
import { publish, MessageContext } from 'lightning/messageService';
import selectedEntity from '@salesforce/messageChannel/Bot_EntityId__c';
import BaseChatHeader from 'lightningsnapin/baseChatHeader';
export default class BotChatHeader extends BaseChatHeader {
/**
* Text to display in h2 element.
* @type {string}
*/
text;
isLiveChatButtonDisplay = false;
@wire(MessageContext)
messageContext;
/**
* Set handlers for events from the sidebar.
*/
connectedCallback() {
this.isLiveChatButtonDisplay = false;
this.assignHandler("prechatState", (data) => {
this.setText(data.label);
});
this.assignHandler("offlineSupportState", (data) => {
this.setText(data.label);
});
this.assignHandler("waitingState", (data) => {
this.setText(data.label);
});
this.assignHandler("waitingEndedState", (data) => {
this.setText(data.label);
});
this.assignHandler("chatState", (data) => {
this.setText(data.label);
this.isLiveChatButtonDisplay = true;
});
this.assignHandler("chatTimeoutUpdate", (data) => {
this.setText("You will time out soon.");
});
this.assignHandler("chatTimeoutClear", (data) => {
this.setText(data.label);
});
this.assignHandler("chatEndedState", (data) => {
this.setText(data.label);
});
this.assignHandler("reconnectingState", (data) => {
this.setText(data.label);
});
this.assignHandler("postchatState", (data) => {
this.setText(data.label);
});
this.assignHandler("chatConferenceState", (data) => {
this.setText(data.label);
});
}
setText(str) {
if (typeof str !== "string") {
throw new Error("Expected text value to be a `String` but received: " + str + ".");
}
this.text = str;
}
//clicking the div fires this event
handleClick(event) {
let msg = 'Representative please';
let payload = { botMsg: msg };
publish(this.messageContext, selectedEntity, payload);
}
}
|
BotChatHeader.js-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>54.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightningSnapin__ChatHeader</target>
</targets>
</LightningComponentBundle>
Take .css file from documentation.
3. Create Chat Message Component
<template>
<div class={messageStyle}>
<lightning-formatted-rich-text
value={content}>
</lightning-formatted-rich-text>
</div>
</template>
BotChatMessage.js
Few important points:
- Defining the scope where subscriber component receives the message in our application. Here APPLICATION_SCOPE has been used.
- Scope feature is only available using @wire(MessageContext).
- There are methods to subscribe, unsubscribe and import message channel for using it.
- In the subscribe method, you can see arrow function has been used so it can call any methods of the class using this operator. Scope can be passed as parameter.
- handleMessage() method retrieves the bot message and post as window's message. For this extra configuration is needed which has been mentioned after.
Entire js file as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92 | import BaseChatMessage from 'lightningsnapin/baseChatMessage';
import { wire } from 'lwc';
// Import message service features required for subscribing and the message channel
import {
subscribe,
unsubscribe,
APPLICATION_SCOPE,
MessageContext
} from 'lightning/messageService';
import botEntity from '@salesforce/messageChannel/Bot_EntityId__c';
const CHAT_CONTENT_CLASS = 'chat-content';
const AGENT_USER_TYPE = 'agent';
const CHASITOR_USER_TYPE = 'chasitor';
const SUPPORTED_USER_TYPES = [AGENT_USER_TYPE, CHASITOR_USER_TYPE];
var showLiveAgentDialog = false;
export default class BotChatMessage extends BaseChatMessage {
subscription = null;
/**
* Displays a chat message using the inherited api messageContent
* and is styled based on the inherited api userType
* and messageContent api objects passed in from BaseChatMessage.
*/
messageStyle = '';
content = '';
@wire(MessageContext)
messageContext;
isSupportedUserType(userType) {
return SUPPORTED_USER_TYPES.some((supportedUserType) => supportedUserType === userType);
}
// Standard lifecycle hooks used to subscribe and unsubsubscribe to the message channel
connectedCallback() {
this.subscribeToMessageChannel();
showLiveAgentDialog = false;
if (this.isSupportedUserType(this.userType)) {
this.messageStyle = `${CHAT_CONTENT_CLASS} ${this.userType}`;
} else {
throw new Error(`Unsupported user type passed in: ${this.userType}`);
}
this.content = this.messageContent.value;
}
disconnectedCallback() {
this.unsubscribeToMessageChannel();
}
// Encapsulate logic for Lightning message service subscribe and unsubsubscribe
subscribeToMessageChannel() {
if (!this.subscription) {
this.subscription = subscribe(
this.messageContext,
botEntity,
(message) => this.handleMessage(message),
{ scope: APPLICATION_SCOPE }
);
}
}
//This is post the message using window's postMessage
handleMessage(message) {
console.log('handleMessage',message.botMsg);
if(!showLiveAgentDialog){
window.postMessage(
{
message: message.botMsg,
type: "chasitor.sendMessage"
},
window.parent.location.href
);
showLiveAgentDialog =true;
}
}
unsubscribeToMessageChannel() {
unsubscribe(this.subscription);
this.subscription = null;
showLiveAgentDialog =false;
}
get isAgent() {
return this.userType === 'agent';
}
}
|
BotChatMessage.js-meta.xml
It will have a target as lightningSnapin__ChatMessage
Take .css file from documentation.
4. Window's message snippet
Add the bot message to be posted as window's message so following code to be added in Head Markup at Community from Settings -> Advanced.
<script>
window.addEventListener("message", receiveMessage, false);
function receiveMessage(event) {
var payload = event.data;
if(payload && payload.type === "chasitor.sendMessage") {
embedded_svc.postMessage("chasitor.sendMessage", payload.message);
}
};
</script>
5. Define LWC Components in Deployment Settings
Go to Embedded Service Deployment Settings and choose Customer Service and define as follows:
Lets publish the Community and test the functionality as follows.
From one browser, choose Service Console App and Omni-channel, choose agent as online.
From other browser, open the community and choose "Chat with an expert".
For detailed interaction, refer the video.
Finally we are done and thanks for reading.