Interactive Templates
Create templates that have interactive content, for example, buttons or forms.
Custom rich content messages are interactive templates that can be inserted in the chat by agents, and the interactive content is seen by customers in the chat window. They appear as regular chat templates for the agent in Communication Panel. They can contain any type of content including scripts and styles. To achieve unified look across all user interfaces, it is recommended to use Bootstrap CSS classes.
Interactive templates are only supported with web chats, not within social or SMS chats.
Prerequisites
-
You must have rights to manage reply template folders and view queues.
-
An anonymous user who has rights to view the templates has been created.
For more information, see Anonymous User.
Creating Interactive Templates
An interactive template provides a powerful tool to manipulate the system, and therefore you should only use content you can trust. Never use content from an unknown source, and test all content in a test system before adapting them to a real production use.
-
On the System Configurator main screen, choose
. -
Choose Add New.
-
Choose Reply Template and click OK.
-
In the Basics block, do the following:
-
Enter a name for the template.
-
Enter description. This field is optional.
-
Select the language used in template. This field is mandatory.
If you have Chatlayer agent bot and you want to use quick reply buttons, the interactive reply template language needs to be English.
-
Choose Interactive for content type.
-
Enter the content.
A template needs to have a callback function initiated by the user that resolves the template. There are certain callbacks the system sets up that should be wired inside your template:
-
resolveTemplate(result:string,resultHtml:string)
This resolves the template with calculated response. Result is a machine-readable textual answer for the template. Optionally you can provide resultHtml to show a html presentation of the answer instead of the text.
-
rejectTemplate()
Callback for specifically rejecting the template by the user. Use this with cancel buttons.
-
onChatMessage(message:string)
System calls this function whenever user inserts a new message. This allows the template to be resolved directly from the typed answer.
samplecode:<script> function submit(node) { resolveTemplate(node.innerText); } function cancel() { rejectTemplate() } function onChatMessage(msg) { // resolve the template if user types in one of the options if (msg.lowerCase().search(/^option [1-6]$/) || msg.lowerCase() === "cancel") { resolveTemplate(msg); } } </script> <div class="list-group w-100"> <a onclick="submit(this)" href="#" class="list-group-item list-group-item-action">Option 1</a> <a onclick="submit(this)" href="#" class="list-group-item list-group-item-action">Option 2</a> <a onclick="submit(this)" href="#" class="list-group-item list-group-item-action">Option 3</a> <a onclick="submit(this)" href="#" class="list-group-item list-group-item-action">Option 4</a> <a onclick="cancel()" href="#" class="list-group-item list-group-item-action">Cancel</a> </div>
-
-
- To enable agents to search for this template in Communication Panel, add the
template name or other descriptive term as a keyword in the block Keywords.
Attachments are not supported with interactive content.
-
In the Template Folders block, add the folders in which the template is available.
This is mandatory since reply templates must be linked to a folder.
-
Save the template.
Example Templates
Here are some example templates.
Buttons
<script>
function submit(node) {
resolveTemplate(node.innerText);
}
function cancel() {
rejectTemplate();
}
function onChatMessage(msg) {
// resolve the template if user types in one of the options
if (msg.toLowerCase().search(/^option [1-6]$/) !== -1) {
resolveTemplate(msg);
}
}
</script>
<div class="d-flex flex-column">
<h6>Please select one of the options below:</h6>
<div>
<button onclick="submit(this)" type="button" class="btn btn-outline-primary btn-sm m-1">Option 1</button>
<button onclick="submit(this)" type="button" class="btn btn-outline-primary btn-sm m-1">Option 2</button>
<button onclick="submit(this)" type="button" class="btn btn-outline-primary btn-sm m-1">Option 3</button>
<button onclick="submit(this)" type="button" class="btn btn-outline-primary btn-sm m-1">Option 4</button>
<button onclick="submit(this)" type="button" class="btn btn-outline-primary btn-sm m-1">Option 5</button>
<button onclick="submit(this)" type="button" class="btn btn-outline-primary btn-sm m-1">Option 6</button>
<button onclick="cancel()" type="button" class="btn btn-outline-primary btn-sm m-1">Cancel</button>
</div>
</div>
Form
<script>
function submitForm() {
var fields = ["Select", "Email", "Password", "Date", "Time", "Range", "Checkbox1", "Checkbox2", "Radio1", "Radio2", "Switch"];
var htmlResult = "";
var result = "";
for (var field of fields) {
var node = document.body.querySelector("#" + field);
var value = (node.type === "checkbox" || node.type === "radio" ? node.checked : node.value);
htmlResult += `<small>${field}</small><p>${value}</p>`;
result += `${field}=${value},`;
}
resolveTemplate(result, `<div>${htmlResult}</div>`);
}
function cancelForm() {
rejectTemplate();
}
function validateEmail(input) {
// custom validator
input.classList.remove("is-valid", "is-invalid");
input.classList.add((input.value.indexOf("@company.com") !== -1 ? "is-valid" : "is-invalid"));
}
</script>
<form class="border border-primary rounded p-3 w-100" onsubmit="submitForm()">
<div class="form-group">
<label for="Select">Select</label>
<select class="form-control" id="Select" aria-describedby="selectHelp">
<option>First topic</option>
<option>Second topic</option>
<option>Third topic</option>
</select>
<small id="selectHelp" class="form-text text-muted">Select a topic for the form</small>
</div>
<div class="form-group">
<label for="Email">Email</label>
<input oninput="validateEmail(this)" type="email" class="form-control" id="Email" required>
<div class="valid-feedback">
Looks good!
</div>
<div class="invalid-feedback">
Must be in company.com domain
</div>
</div>
<div class="form-group">
<label for="Password">Password</label>
<input type="password" class="form-control" id="Password" required minlength="8" maxlength="12">
</div>
<div class="form-group">
<label for="Date">Date</label>
<input type="date" class="form-control" id="Date" min="1985-04-01" max="2030-04-20" required>
</div>
<div class="form-group">
<label for="Time">Time</label>
<input value="12:00" type="time" class="form-control" id="Time">
</div>
<div class="form-group">
<label for="Range">Range</label>
<input value="2" type="range" min="0" max="10" class="custom-range" id="Range" required>
</div>
<div class="form-group">
<div class="custom-control custom-checkbox custom-control-inline">
<input type="checkbox" class="custom-control-input" id="Checkbox1">
<label class="custom-control-label" for="Checkbox1">Option 1</label>
</div>
<div class="custom-control custom-checkbox custom-control-inline">
<input type="checkbox" class="custom-control-input" id="Checkbox2">
<label class="custom-control-label" for="Checkbox2">Option 2</label>
</div>
</div>
<div class="form-group">
<div class="custom-control custom-radio custom-control-inline">
<input type="radio" id="Radio1" name="customRadioInline1" class="custom-control-input">
<label class="custom-control-label" for="Radio1">Radio Option 1</label>
</div>
<div class="custom-control custom-radio custom-control-inline">
<input type="radio" id="Radio2" name="customRadioInline1" class="custom-control-input" checked>
<label class="custom-control-label" for="Radio2">Radio Option 2</label>
</div>
</div>
<div class="form-group custom-control custom-switch">
<input type="checkbox" class="custom-control-input" id="Switch">
<label class="custom-control-label" for="Switch">Switch</label>
</div>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-sm btn-outline-primary">Submit</button>
<button onclick="cancelForm()" class="btn btn-sm btn-link">Cancel</button>
</div>
</form>
List
<script>
function submit(node) {
resolveTemplate(node.innerText);
}
function cancel() {
rejectTemplate()
}
function onChatMessage(msg) {
// resolve the template if user types in one of the options
if (msg.toLowerCase().search(/^option [1-6]$/) !== -1) {
resolveTemplate(msg);
}
}
</script>
<div class="list-group w-100">
<a onclick="submit(this)" href="#" class="list-group-item list-group-item-action">Option 1</a>
<a onclick="submit(this)" href="#" class="list-group-item list-group-item-action">Option 2</a>
<a onclick="submit(this)" href="#" class="list-group-item list-group-item-action">Option 3</a>
<a onclick="submit(this)" href="#" class="list-group-item list-group-item-action">Option 4</a>
<a onclick="cancel()" href="#" class="list-group-item list-group-item-action">Cancel</a>
</div>
Slider
<script>
function submit() {
resolveTemplate(document.querySelector("#rangeInput").value);
}
function cancel() {
rejectTemplate()
}
function onChatMessage(msg) {
// resolve the template if user types in one of the options
if (msg.search(/^[0-9]$/) !== -1) {
resolveTemplate(msg);
}
}
</script>
<style>
datalist {
display: flex;
width: 100%;
justify-content: space-between;
padding: 0 3px 0 3px;
}
option {
width: 2ex;
display: flex;
justify-content: center;
}
/* FF */
input[type=range]::-moz-range-progress {
background-color: var(--primary);
}
/* IE */
input[type=range]::-ms-fill-lower {
background-color: #007bff;
}
</style>
<div class="rounded border border-primary p-3 w-100">
<input type="range" min="0" max="10" value="5" step="1" list="tickmarks" id="rangeInput" class="custom-range">
<datalist id="tickmarks">
<option>0</option>
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
<option>6</option>
<option>7</option>
<option>8</option>
<option>9</option>
<option>10</option>
</datalist>
<div class="d-flex justify-content-end mt-2">
<button onclick="submit()" class="btn btn-sm btn-outline-primary">Submit</button>
<button onclick="cancel()" class="btn btn-sm btn-link">Cancel</button>
</div>
</div>
Stars
<script>
var selected;
function submit() {
var reply = "";
for (var i = 0; i < 5; i++) {
reply += (i <= selected ? "<span style='color: orange;font-size: xx-large'>★</span>" : "<span style='color: gray;font-size: xx-large'>★</span>");
}
resolveTemplate(`${selected}/5`, `<div>${reply}</div>`);
}
function cancel() {
rejectTemplate()
}
function onChatMessage(msg) {
// resolve the template if user types in one of the options
if (msg.search(/^[1-5]$/) !== -1) {
selected = parseInt(msg)-1;
this.submit();
}
}
function activate(star) {
var stars = Array.from(star.parentNode.children);
selected = stars.indexOf(star);
for (var [index, node] of stars.entries()) {
if (index > selected) {
node.classList.remove("selected");
} else {
node.classList.add("selected");
}
}
}
</script>
<style>
.star {
font-size: xx-large;
cursor: pointer;
}
.selected::before {
color: orange !important;
content: "★" !important;
}
.star::before {
content: "☆";
color: gray;
}
.star:hover::before {
color: yellow !important;;
content: "★";
}
</style>
<div class="w-100 d-flex justify-content-center p-2">
<div class="border border-primary p-1 pl-2 pr-2 d-flex align-items-center rounded flex-wrap">
<span>Rating:</span>
<span class="ml-1 mr-1 mb-1">
<span onclick="activate(this)" class="star"></span>
<span onclick="activate(this)" class="star"></span>
<span onclick="activate(this)" class="star"></span>
<span onclick="activate(this)" class="star"></span>
<span onclick="activate(this)" class="star"></span>
</span>
<button onclick="submit()" class="btn btn-sm btn-outline-primary">Submit</button>
<button onclick="cancel()" class="btn btn-sm btn-link">Cancel</button>
</div>
</div>