Skip to main content

Website Widget

Add a floating assistant to your website so visitors can talk, chat, or video with an AI concierge — ask questions, get guided, and hear answers grounded in your own content. You create and configure the widget in Erdo, then drop one line of code on your site. Everything runs through Erdo; your site never loads a third-party SDK or holds any keys.
The widget is a website embed, separate from outbound phone calls. Same agent technology, different surface: here a visitor starts the conversation from your page.

Create a widget

Everything below — modes, voice, and branding — is configured in Settings → Voice widgets, so the embed snippet stays a single line and you never have to hand-edit code to change how the widget looks or sounds.
1

Open Settings → Voice widgets

Click New widget and give it a name.
2

Choose its modes

Pick any combination of Voice (talk out loud), Chat (type messages), and Video (an on-screen avatar). With more than one selected, visitors get a switcher to move between them.
3

Pick a voice

Search the voice library and preview candidates, then select one — or leave it on the default. This is the spoken voice for the voice mode.
4

Pick a video avatar (video mode only)

When Video is enabled, choose the on-screen avatar visitors see. The picker shows each available avatar as a thumbnail that plays a short preview on hover — select one, or leave it on the default avatar.
5

Describe the concierge

Set its greeting, what it helps with and its tone, plus any compliance guardrails it must always follow.
6

Brand it

Set the accent colour and the header / button / intro copy. A live preview in the dialog shows your changes before you save — see Match your brand.
7

Let visitors book meetings (optional)

Connect a calendar and enable meeting scheduling so the assistant can offer real open slots and book meetings during the conversation — see Book meetings on your calendar.
8

Set who can embed it (optional)

Add the allowed origins for your site — see Allowed origins below. Leave it empty while testing.
9

Copy the embed snippet

Each widget has a one-line <script> snippet. Copy it from the widget card.

Widget settings

Every setting lives on the widget itself, so changing any of them never touches the snippet on your site — the embedded widget picks the new configuration up automatically. The full set, and what each controls:

Embed it on your site

Paste the snippet once into your site’s HTML, just before the closing </body> tag (or in your CMS / theme’s “custom code” / footer area), on every page where you want the assistant:
It adds a floating launcher at the bottom of the page — a compact card with the concierge’s animated orb (or a face, if you pick one) above a call-to-action — and nothing else on your page changes. Visitors tap it to start. The widget’s modes, voice, and branding all come from its settings — the snippet itself never needs to change when you tweak them. By default the launcher shows the plain animated orb. In the widget’s Appearance settings you can give the concierge a face instead — pick one of a set of preset faces. A video widget is the one exception: it always shows its selected avatar’s own photo, so the launcher matches the avatar visitors are about to meet. Whatever you choose appears inside the conversation too — in the orb a visitor taps to start a call and while the call is live — so the concierge stays one consistent presence.
In the dashboard, each widget has an embed builder (“Customize” next to the snippet). It generates this snippet for you and, if you want per-page tweaks, adds the data-erdo-* overrides below — hide the launcher, set a language, or override copy/colours — with a live preview. Leave a field blank to inherit the widget’s saved setting.
Pages you build inside Erdo (the “make me a page” flow) that embed a widget work automatically — Erdo’s own page hosts are always allowed, so you don’t need to add them to the allowed origins.

Preview your widget on a demo page

Before you drop the snippet on your own site — or when you just want to show a colleague — each widget card in Settings → Voice widgets has a Preview button. It opens a public demo page in a new tab: a placeholder website for a fictional real-estate development with your widget embedded on it, running exactly as it would on a real page. The widget pulls its modes, voice, and branding from its settings and grounds its answers in the demo site’s content, so you can start a conversation and ask about the development’s prices, viewing hours, or buying process to hear how the concierge behaves in context. The demo page is a shareable, no-login link — anyone you send it to can open it and try the widget without an Erdo account (the same vw_ key that’s designed for public embedding). It’s the quickest way to get sign-off before you touch your own site’s code. The page has a Floating / Inline panel toggle at the top so you can see both embed styles: the default floating launcher in the bottom corner, and the always-open inline panel that fills a section of the page. Switching between them reloads the demo with that style applied.
The demo works even while your allowed origins are locked down to your own site — Erdo’s own hosts are always allowed, so the demo page never needs to be in the list. If the widget is disabled, the demo page still loads the placeholder site but shows a banner instead of the widget; enable the widget to try it.

Conversation modes — voice, text, and video

One widget, one snippet — the same assistant can talk (voice), chat (text), or appear as a video agent. You choose which modes a widget offers; all three are answered by the same assistant, grounded in the same Knowledge, so the experience is consistent however a visitor reaches out. When a widget offers more than one mode, visitors see a small Talk / Chat / Video switcher; with a single mode they just get that experience. Permissions are only requested when a visitor actually starts that mode — a voice- or text-only widget never prompts for the camera. For the Video mode you can also pick which on-screen avatar appears (see the avatar step above); leave it on the default to use Erdo’s standard avatar.
Your existing snippet doesn’t change. Turning on text or video for a widget is a setting on the widget itself — the <script> tag you’ve already embedded picks the new modes up automatically. Widgets default to voice only, so nothing changes until you opt in.

Give the assistant knowledge

The widget answers from your workspace’s Knowledge: publish the facts it may use, attach photos and videos to them, and the assistant both answers visitors’ questions and shows them what it’s describing. You never wire content to a specific widget — every widget in the organization draws from the same published Knowledge.

What the assistant can answer from

The widget talks to anonymous visitors on the open web, so it deliberately does not see everything in your workspace. It answers only from Knowledge that is both:
  1. Public — the entry’s visibility is set to Public, opting it into external surfaces. Every new Knowledge entry starts as Workspace (organization-internal), so nothing is exposed by default.
  2. Approved — making an entry public approves a draft in the same step, so publishing is all you need; entries approved through the review flow also qualify once made public.
An entry that is approved but still Workspace is invisible to the widget — if the assistant keeps saying it doesn’t have information you know you’ve added, this is almost always why. To publish content, either ask Erdo in chat (for example “make the property gallery and FAQ Knowledge public”) or open Knowledge, select the entry, and change its visibility to Public. Only publish customer-facing facts you’re happy to tell any visitor — products, pricing, opening hours, locations, policies, FAQs, photo galleries. Internal notes and anything sensitive should stay Workspace.

Showing photos and videos

In every mode — talking, typing, or on a video call — the assistant can show what it’s describing: a photo of the lobby, a residence, a product — pulled straight from your Knowledge. To give it something to show, attach the images or videos to a Knowledge entry (a photo gallery, a product sheet) and publish it like any other entry. The assistant finds the best-matching media and displays it in the widget; you don’t configure anything per widget, and it only ever shows media attached to Knowledge that is public and approved (see What the assistant can answer from). On a video call, the avatar shrinks aside so the photos take the stage while it keeps talking. In the compact floating panel these appear as cards in the conversation. When the widget is expanded to fullscreen (or embedded in a page tab), it opens a two-pane showcase: the conversation stays on the left while a large image portal fills the right, with a row of thumbnails to click through and any matching video playable inline. Each item can carry a short caption and a highlight (for example a price). Tap the main image to view it full-size.

Book meetings on your calendar

A widget can let visitors book a meeting with your team during the conversation — in any mode. A visitor asks about a demo, the assistant checks your live calendar availability, offers real open slots, collects the visitor’s name and email, and books the meeting. The visitor gets the calendar invite by email from your calendar provider; nothing else is needed from them. Booking works the same way whether the visitor is talking, typing, or on a video call, and it always lands on your organization’s connected calendar. Three calendar providers are supported, each with its own way of describing what gets booked: To set it up:
  1. Connect the calendar provider in Settings → Connectors (once, for the organization).
  2. Enable scheduling on the widget and pick the provider — plus the event type (Calendly / Cal.com) or the calendar and default meeting length (Google). Two ways: ask Erdo in chat (“let visitors book meetings through the Acme widget using our Cal.com”), or edit the widget in Settings → Voice widgets (the Meeting scheduling section).
The assistant only ever offers times it just read from your calendar — if it can’t read availability (for example the connection was revoked), it says so and suggests another way to get in touch rather than guessing. Times are offered in the visitor’s own timezone.

Conversation transcripts & follow-up

Every widget conversation — voice, text, or video — is saved in your workspace, so a visitor question is never lost when the tab closes. Each conversation keeps its full transcript along with the mode it used, the page it started on, when it happened, how long it lasted, and a short auto-generated summary of what the visitor wanted. You review them by asking Erdo in chat:
  • List conversations“what did visitors ask the Acme widget this week?”, “show me yesterday’s widget conversations”. Erdo lists them newest first with their summaries, so you can scan what visitors are asking without opening each one.
  • Read one back“pull up the conversation where someone asked about enterprise pricing”, or point at one from the list. Erdo reads back the full exchange, exactly as the visitor and the assistant said it.
Because the transcripts are ordinary workspace data for Erdo, you can go beyond listing: ask it to summarize the week’s themes, count how many visitors asked about a topic, or draft follow-up emails from what was said. The assistant also asks visitors for their name and the best way to reach them — naturally, once it understands what they’re looking for, and whether or not meeting booking is enabled. It never withholds an answer to get contact details and drops the subject if the visitor declines. Details a visitor shares are part of the saved transcript, so following up is as simple as asking Erdo “which widget visitors left contact details this week?”. Transcripts are visible to your workspace members through Erdo — treat them like any other customer communication.

Read conversations programmatically

The same list-and-read surface is available over the REST API and to MCP clients, so a scheduled automation or an external dashboard can pull conversations without going through chat. Both are org-scoped to the caller’s credentials and identify a widget by its name or public key (vw_…), never an internal id:
  • ListGET /v1/voice/widget-conversations?widget=Acme%20Concierge (or a POST with a JSON body) returns each conversation’s session id, mode, timing, duration, and summary, newest first and paginated. MCP tool: erdo_voice_widget_conversation_list.
  • Read onePOST /v1/voice/widget-conversations/get with {"widget": "…", "session_id": "…"} returns the rendered transcript, the raw transcript, and — for voice conversations — a structured turns array. MCP tool: erdo_voice_widget_conversation_get.
Each entry in turns is one assistant turn that drove the language model, with the fields ops teams watch for latency and cost monitoring: A typical use is an hourly automation that reads recent conversations and appends the per-turn latency rows to a dataset, so you can chart TTFB and fail-over rate over time. Text and video conversations carry no model metrics, so their turns array is empty.

Match your brand

Set the widget’s accent colour and copy in Settings → Voice widgets — the dialog shows a live preview as you type, and the branding is saved on the widget, so the same one-line snippet always reflects your latest look: The widget runs in a sandboxed frame, so its inside is styled by these settings, not your page’s CSS. To target the widget’s container (position, size, z-index) from your own CSS, it has a stable id/class: #erdo-voice-widget / .erdo-voice-widget.

Per-page overrides (advanced)

If a single widget appears on pages that need different branding, you can override any branding field for one page with a data-erdo-* attribute on the embed script. A present attribute wins over the widget’s saved setting; anything you omit falls back to the saved value.
Together, data-erdo-bg / text / muted / border (plus accent) let you run the widget in a fully dark or branded palette. Colours must be hex; anything else is ignored and the default is kept.
Style only the container box (position, size, z-index, shadow) with your CSS. Never apply a colour filterhue-rotate, invert, sepia, grayscale — to the widget element to recolour it. A filter on the iframe re-tints its entire rendered surface, including the photos the assistant shows during a call, so a blue sky turns orange and green turns purple. Use the data-erdo-* colour attributes above instead — they restyle the chrome without ever touching the images.

Language & translation

The widget speaks your visitor’s language on two levels: its own chrome (buttons, status, hints, placeholders) and the assistant’s replies. It follows the page automatically. If your page declares a language — <html lang="es">, <html lang="pt-BR"> — the widget picks it up with no extra configuration: the chrome is translated, and both the voice and video avatar conversations speak that language. Set data-erdo-lang on the embed to override the page’s language for the widget specifically:
Your own copy always wins. Any text you customized — in the widget settings or via a data-erdo-* attribute (title, intro, launcher CTA/tagline, button labels) — is shown exactly as you wrote it and is never auto-translated. Only the copy you leave at its default gets the built-in translation. So a single widget can serve a localized page in that language out of the box, while still honouring any wording you set yourself. Translations currently ship for a starter set of languages; any language not yet translated falls back to English per string (a partial translation never shows a blank). Give each language its own voice. In the widget’s settings, under Voice & languages, you set a primary language and can add extra languages — up to 10 in total — each with its own voice picked from the voice library. The agent then answers every configured language in that language’s voice (so Spanish sounds like a native Spanish speaker, not an English voice reading Spanish), and your greeting is translated into each language automatically. This is one agent serving all of them: a data-erdo-lang page (or a visitor who switches language) is met in the right voice with no per-page setup. Leave the extra languages empty and the widget stays single-language.

Open it from your own button, script, or agent

By default the widget shows a floating launcher. You can also drive it yourself — useful for a custom “Talk to us” button, a help menu, or an in-page assistant. Declaratively — add a data-erdo-voice-* attribute to any element; clicking it controls the widget (no JavaScript needed):
Programmatically — call the global API from any script:
Opening the widget — whether the visitor taps the launcher or you call open() / toggle() / expand() — goes straight into the call: on a voice widget it asks for the microphone and connects, so there’s no second tap on the orb. If the visitor declines the microphone prompt, the call ends and the widget stays open on its maximized screen, where they can type a question in chat or tap the orb to try the call again. (Because a browser only starts audio in response to a real click, call open() from within a click handler so the microphone prompt appears reliably.) Calls made before the widget finishes loading are queued and run once it’s ready. Visitors can also expand to fullscreen with the ⤢ button in the widget header, and tap any photo to view it full-size.

Hide the built-in launcher and use your own call-to-action

Add data-erdo-launcher="none" to the embed to suppress the floating pill entirely. The widget mounts hidden — no launcher, and nothing that intercepts clicks — so your page owns the call-to-action and opens the widget whenever you choose:
Or open it from a script — for example on scroll, after a delay, or from your own UI:
Keep your CTA in sync. The widget can be closed by the visitor too (the ✕, the Escape key, or clicking outside it). Listen for state changes so your button always reflects whether the widget is open:

Embed it inline as a panel (no floating bubble)

Add data-erdo-embed="panel" to mount the widget inline, as an always-open panel that fills a container — a concierge section, a sidebar, a modal you own — instead of a floating launcher. Point it at the container with data-erdo-target="#your-element" (or, with no target, it mounts into the embed script’s own parent element):
The panel is always open, has no launcher pill, and never takes over the viewport — the container controls its size (the iframe fills its width and height, so give the container a height). The panel shows its own Start call button on an orb: voice and video both start on a tap, never automatically — so the panel can sit in the page without grabbing the microphone on load. Every appearance attribute above still applies, including the dark panel chrome (data-erdo-bg / -text / -muted / -border) if you want it to read as part of the section rather than a light box.

Allowed origins

Allowed origins restrict which websites may embed this widget, so someone can’t copy your snippet onto their own site and run up your usage. Leave the list empty to allow any site (handy while testing); add origins to lock it down — up to 50 per widget. The rules — the widget shows an error and won’t start on a site that doesn’t match:
  • Scheme + domain only. Enter the full origin including https://, with no path: https://acme.com, not acme.com and not https://acme.com/contact.
  • No wildcards. *.acme.com is not supported.
  • Matching is exact, and subdomains count as different sites. https://acme.com does not cover https://www.acme.com or https://shop.acme.com — add each one you actually use, on its own line.
  • Matching ignores case and a trailing /.
The most common mistake: adding https://acme.com but serving your site from https://www.acme.com (or vice-versa). They’re different origins — list every hostname your visitors actually load.
Example — a site served from both the apex and www:

Usage limits

Each widget has a daily session cap (how many conversations it will start per day) to keep usage predictable — 500 per day unless you change it, and 0 means unlimited. Every mode counts toward the same cap — a voice call, a text chat, and a video session each use one conversation. When the cap is reached, the widget tells visitors it’s unavailable until the next day. Raise or lower it in the widget’s settings.

Troubleshooting