Help us improve our product documentation on docs.cognigy.com by sharing your thoughts in a quick survey. Your feedback shapes the future of our content!
Help us improve our product documentation on docs.cognigy.com by sharing your thoughts in a quick survey. Your feedback shapes the future of our content!
Use this file to discover all available pages before exploring further.
By the end of this guide, you will have learned how to set up a Click To Call widget that includes a selector field. The selector field will be displayed as an alternative to the voice input field to select predefined options. A selector field can be useful during voice conversations when the end user needs to select from a set of options, for example, when choosing a menu in a cantina setting.
Configure a Flow with an AI Agent Node and a Question Node. The Flow handles the conversation and opens the selector field on the Click To Call widget.
Configure a Voice Gateway Endpoint. The Voice Gateway Endpoint connects the Flow to Voice Gateway and activates the Click To Call widget.
Embed and test the widget. Add the widget script to your page and see the Click To Call widget working.
Click + New Endpoint, select Voice Gateway and configure the following:
Name — for example, Click To Call Cantina Support.
Flow — Select the Flow you previously configured, in this example, Click To Call Assistant.
Click Save.
2
Generate the Click To Call Embedding Code
In the Endpoint settings, find Click To Call Embedding HTML.
Click the Set Up Click To Call Integration button in that field to generate the embedding code in the code editor. Hover over the code editor and click the Copy to clipboard button. You will use this code to embed the Click To Call widget in your website.
3
Enable and Configure the Click To Call Widget
In Click To Call Widget Settings:
Enable Click To Call Widget — activate the toggle.
AI Agent Name — Name shown on the widget, for example, Cantina Support.
Tagline — Short text under the name, for example, Let me know what you want to eat!.
(Optional)AI Agent Avatar Logo URL — Add a URL of the image shown on the widget, for example, https://www.<domain>.com/logo.png. If empty, the Cognigy.AI logo is used.
(Optional)Theme — select the color theme of the widget.
Where <ENDPOINT_URL> and <YOUR_ENDPOINT_CONFIG_TOKEN> are the URL and the Endpoint configuration token, respectively. For example, https://endpoint-dev.cognigy.ai/ab8b929039b427fed7ee84bb799acd7f254fc9254be27c87a78fc8a70fb048ec for the development environment or https://endpoint.cognigy.ai/ab8b929039b427fed7ee84bb799acd7f254fc9254be27c87a78fc8a70fb048ec for the production environment.
Make sure the actual Endpoint configuration URL is the same as the one you copied from Click To Call Embedding HTML in the Voice Gateway Endpoint.
Edit the widget script to add the dropdown menu and events to open and close the selector when the Flow sends openInput: true or closeInput: true in the Say Nodes. The following code is an example of how to do this:
<script src="https://github.com/Cognigy/click-to-call-widget/releases/latest/download/webRTCWidget.js"></script><script> addEventListener("load", function () { if (typeof window.initWebRTCWidget !== "function") return; var token = "<ENDPOINT_URL>/<YOUR_ENDPOINT_CONFIG_TOKEN>"; window.initWebRTCWidget(token).then(function (widget) { var currentSession = null; // Returns the widget container element (tries vc_, voice_connect_, and webrtc_ class names). function getWidgetContainer() { return document.querySelector(".vc_widget_container") || document.querySelector(".voice_connect_widget_container") || document.querySelector(".webrtc_widget_container") || document.querySelector("[class*='widget_container']"); } // Creates and shows a selector (dropdown) inside the transcript container or below the widget. Options: Mediterranean, Light, Comfort, Vegetarian. On Submit, sends the value via session.sendInfo() and hides the selector. function showSelectorField(session) { currentSession = session; var wrap = document.getElementById("widget-selector-wrap"); if (wrap) { wrap.style.display = "block"; return; } var widgetEl = getWidgetContainer(); if (!widgetEl) widgetEl = document.body; wrap = document.createElement("div"); wrap.id = "widget-selector-wrap"; wrap.style.cssText = "width:100%;max-width:460px;margin-top:8px;margin-bottom:8px;box-sizing:border-box;display:block;"; var select = document.createElement("select"); select.id = "widget-menu-select"; select.style.cssText = "width:100%;padding:8px 12px;font-size:14px;border:1px solid #ccc;border-radius:6px;box-sizing:border-box;margin-bottom:8px;"; select.setAttribute("aria-label", "Choose a menu"); var placeholder = document.createElement("option"); placeholder.value = ""; placeholder.textContent = "Select your menu"; select.appendChild(placeholder); [{ value: "Mediterranean", label: "Mediterranean" }, { value: "Light", label: "Light" }, { value: "Comfort", label: "Comfort" }, { value: "Vegetarian", label: "Vegetarian" }].forEach(function (opt) { var option = document.createElement("option"); option.value = opt.value; option.textContent = opt.label; select.appendChild(option); }); var btn = document.createElement("button"); btn.type = "button"; btn.textContent = "Submit"; btn.style.cssText = "width:100%;padding:8px 12px;font-size:14px;border:1px solid #ccc;border-radius:6px;box-sizing:border-box;cursor:pointer;"; btn.setAttribute("aria-label", "Submit"); function submitSelection() { var value = select.value ? select.value.trim() : ""; if (!value) return; if (currentSession && typeof currentSession.sendInfo === "function") currentSession.sendInfo(value); hideSelectorField(); } select.addEventListener("change", function () { btn.disabled = !select.value; }); btn.disabled = true; btn.addEventListener("click", submitSelection); wrap.appendChild(select); wrap.appendChild(btn); if (widgetEl === document.body) { widgetEl.appendChild(wrap); } else { var transcriptContainer = document.querySelector(".vc_transcript_container") || document.querySelector(".voice_connect_transcript_container") || document.querySelector(".webrtc_transcript_container") || document.querySelector("[class*='transcript_container']"); if (transcriptContainer) { transcriptContainer.appendChild(wrap); } else { var stack = widgetEl.parentElement; var transcriptWrapper = stack && (stack.querySelector(".vc_widget_transcript_wrapper") || stack.querySelector(".voice_connect_widget_transcript_wrapper") || stack.querySelector(".webrtc_widget_transcript_wrapper")); if (transcriptWrapper) { transcriptWrapper.insertAdjacentElement("afterend", wrap); } else { var contentContainer = widgetEl.querySelector(".vc_widget_content_container") || widgetEl.querySelector(".voice_connect_widget_content_container") || widgetEl.querySelector(".webrtc_widget_content_container"); if (contentContainer) { contentContainer.insertAdjacentElement("afterend", wrap); } else { widgetEl.appendChild(wrap); } } } } } // Hides the selector and clears the current session reference. function hideSelectorField() { currentSession = null; var wrap = document.getElementById("widget-selector-wrap"); if (wrap) wrap.style.display = "none"; } // Returns true if the INFO body contains openInput: true (Flow asks to show the selector). function hasOpenInput(body) { if (body == null) return false; if (typeof body === "string") { try { body = JSON.parse(body); } catch (e) { return false; } } var infoBody = typeof body === "object" ? body : null; if (!infoBody) return false; if (infoBody.openInput === true) return true; if (infoBody.data && infoBody.data.openInput === true) return true; if (infoBody.data && infoBody.data.data && infoBody.data.data.openInput === true) return true; return false; } // Returns true if the INFO body contains closeInput: true (Flow asks to close the selector). function hasCloseInput(body) { if (body == null) return false; if (typeof body === "string") { try { body = JSON.parse(body); } catch (e) { return false; } } var infoBody = typeof body === "object" ? body : null; if (!infoBody) return false; if (infoBody.closeInput === true) return true; if (infoBody.data && infoBody.data.closeInput === true) return true; if (infoBody.data && infoBody.data.data && infoBody.data.data.closeInput === true) return true; return false; } // Runs when a new call (RTC session) starts. widget.on("newRTCSession", function (session) { // Runs when the Flow sends a SIP INFO: show the selector if openInput: true, hide it if closeInput: true. session.on("newInfo", function (ev) { if (ev.originator !== "remote") return; var info = ev.info || ev; var body = info && (info.body !== undefined ? info.body : info.request && info.request.body); if (body === undefined && typeof ev.body !== "undefined") body = ev.body; if (body == null) return; try { if (hasCloseInput(body)) { hideSelectorField(); return; } if (hasOpenInput(body)) showSelectorField(session); } catch (e) {} }); // Runs when the call ends normally; hide the selector. session.on("ended", hideSelectorField); // Runs when the session is terminated; hide the selector. session.on("terminated", hideSelectorField); }); }); });</script>
2
Test the Widget
Open the page in a browser, allow microphone access when prompted, and click on the widget to start a voice conversation with your AI Agent.
After the AI Agent greets you, say you want to select a menu. The selector field opens on the widget.
Try answering the question using the dropdown (Mediterranean, Light, Comfort, Vegetarian) and by voice.