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 website deployment
Everything below — modes, voice, and branding — is configured in Agents → Deployments, so the embed snippet stays a single line and you never have to hand-edit code to change how the widget looks or sounds. A deployment is attached to a durable Erdo agent: edit the agent once to change its identity and instructions everywhere it is deployed. Website visitors can search only knowledge your organization has explicitly marked Public.1
Open Agents → Deployments
Click Website, choose the agent visitors should meet, and give the
deployment 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
Configure the welcome and rules
Set its greeting and any channel-specific compliance guardrails. What the
concierge does and how it behaves come from the attached agent’s Instructions.
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:
data-erdo-minimize-scroll, below), or after 5 seconds
on a page they don’t scroll, whichever comes first. The card
morphs into the pill in one continuous motion — just the orb, the
call-to-action, and the mode it offers. Hovering the pill brings the full card
back; moving away folds it again. Tapping either the pill or the card opens the
widget exactly the same way, and the fold respects a visitor’s reduce motion
setting (it snaps between states instead of animating).
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.
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 website deployment card in Agents → Deployments 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 samevw_ 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:- 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.
- 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.
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 books the meeting. The visitor gets the calendar invite by email from your calendar provider when they shared an address; a visitor who declines to give one still gets the meeting booked, with the time confirmed right there. 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:
- Connect the calendar provider in Settings → Connectors (once, for the organization).
- 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 deployment in Agents → Deployments (the Meetings and leads section).
The “Book a call” form
Some visitors would rather pick a time straight away than talk it through. So whenever meeting scheduling is enabled, the widget also shows a Book a call option they can tap directly — a “Prefer to schedule? Book a call” line on the launcher card, and a calendar button next to the chat input once the widget is open. Either one drops the visitor into a short booking form, without starting a call first. (When scheduling is off, neither appears — nothing about the widget changes.) The form is three quick steps, all in the visitor’s own language and timezone:1
Their details
Name and phone — the same details the assistant
would otherwise collect in conversation. Email is asked for too: it is
required when your calendar provider cannot book without an invitee
(Calendly, Cal.com) and optional otherwise (Google Calendar), so a visitor
who only wants to leave a number can still book.
2
Pick a time
A strip of the next two weeks of days, each showing the real open slots read
live from your calendar, in the visitor’s timezone. Days your schedule has no
openings for — weekends, days off, fully booked days — are left out entirely,
so what’s offered always follows your calendar settings, and there’s a retry
if availability can’t be reached.
3
Confirmation
A confirmation that the meeting is booked, with the day and time and a note
that the calendar invite is on its way by email — or, for a visitor who
booked with only a phone number, the confirmed time alone.
The same booking flow can be laid out inline on a page rather than inside the
widget panel — that’s what a follow-up page uses to let a
captured lead pick a time straight from your autoreply email. It runs on this
widget’s scheduling settings, so connecting a calendar once serves both.
Leads from your widget
A widget produces leads two ways, and both land in the same table. Everyone who fills in the booking form is saved as a lead the moment they enter their name and email and continue to the time picker, before they’ve even chosen a slot — so a visitor who starts booking but doesn’t finish still becomes a contact you can follow up with. And every visitor who gives the assistant their details in conversation — a name, an email, a phone number, in a voice, text or video chat — is saved as a lead too, whether or not booking is enabled at all. Each lead is one row. It carries the contact details (first and last name, email, phone), the page they were on, campaign parameters (utm_*, gclid,
fbclid), and a source column naming which surface it came from:
widget_booking_form for the form, widget_conversation for details given in
conversation. A booked column flips to true — with the meeting’s start
time — when they confirm a slot in the form, and equally when the assistant
books the meeting for them mid-conversation. That makes the follow-up queries
trivial: “who started booking this week but didn’t finish?” is the rows where
booked is false, and “which visitors left their details talking to the
assistant?” is the rows where source is widget_conversation.
Rows are keyed on the person, not on the touch, so the same visitor doesn’t
appear twice however many times they come back. A later touch fills in what an
earlier one left blank rather than overwriting it — a phone number given in
conversation joins the row their form submission created, and the details they
typed stay as they typed them. The person is identified by their email address
where there is one and by their phone number otherwise, so a visitor who leaves
an email once and only a number the next time can still land as two rows.
Where the leads go is a deployment setting (Agents → Deployments → the widget
→ Save leads), resolved in this order:
- A dataset you pick. Choose any dataset you already collect leads in — for example the one your Erdo landing page’s lead form writes to — and every lead this widget produces goes there.
- Your organization’s leads dataset, when you have exactly one. An Erdo landing page creates one, so a customer running pages and a widget gets both streams in one table without configuring anything.
- A “Widget leads” dataset Erdo creates for you, when neither of the above resolves — the first time a lead arrives, complete with a filter that keeps test traffic out of your counts. If your organization has several leads datasets and the widget pins none, leads land here and the deployment settings say so, so you can pin the right one.
?erdo_test=1 (the marker QA and Erdo’s automated checks use) and
the conversations Erdo runs against a widget you have designated for its own
checks are read like any other conversation but never written as a lead.
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.
source = widget_conversation, and a meeting the assistant
booked during the conversation marks that same lead as booked. So following up
is a query over your leads, not a trawl through transcripts. See Leads from
your widget for where those rows land and how to turn
the behaviour off.
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 where a widget is named it is named by its name or public key (vw_…), never an internal id:
- List —
GET /v1/voice/widget-conversations(or aPOSTwith a JSON body) returns each conversation’s session id, mode, timing, duration, summary, the topics the visitor asked about, and the lead it produced, newest first and paginated. It covers every widget in your organization unless you pass?widget=Acme%20Conciergeto narrow it to one, so a dashboard never has to enumerate widgets first — each row names its own withwidget(the public key) andwidget_name. Bound the period withsinceanduntil(RFC3339;sinceinclusive,untilexclusive, so two consecutive months never double-count a conversation), and passcanonical_lead_idto read one lead’s conversations (see below); filters combine.totalis how many conversations match the filter at the moment of that request, regardless of paging — the number to put on a tile. It is live: a conversation that starts while you page through can change it, so a multi-page read is finished when a response has nonext_cursor, not when the rows you have collected reachtotal. When a response includesnext_cursor, pass it back ascursorto read the next stable page with the same filters; this avoids skips when a new conversation starts during a multi-page scan. MCP tool:erdo_voice_widget_conversation_list. - Read one —
POST /v1/voice/widget-conversations/getwith{"session_id": "…"}returns the conversation’s topics, atranscript_turnsarray ([{role, text, at}]— the conversation ready to display, whatever shape it was captured in), the rendered transcript text, the raw transcript, the same lead fields the list carries, and — for voice conversations — a structuredturnsarray of model metrics. The session id identifies the conversation on its own, sowidgetis optional; a session belonging to another organization is never returned. MCP tool:erdo_voice_widget_conversation_get.
pricing, floor plans, booking a tour — written by the same
summarizer that writes the summary, so they appear a few minutes after a
conversation ends rather than the moment it does. topics is null while a
conversation has not been analysed yet and [] once it has been analysed and
nothing stood out. The distinction is worth keeping if you are counting: folding
the two together reports conversations nobody has read yet as conversations about
nothing.
The lead a conversation produced rides the same rows. contact is the
{first_name, last_name, email, phone} the summarizer read out of the
conversation, lead_status is created | existing | disabled | refused |
test, and lead_saved_at is when that outcome was recorded. refused means
the details could not be tied to a single lead — they matched more than one, or
the email and phone pointed at different leads, or the conversation left nothing
in the columns your leads dataset identifies people by — so no row was written
and the conversation was closed out rather than retried. A visitor nobody has
met before is not refused: their details match no existing lead, so a new one is
written and the conversation reads created. See
lead identity. Both absences follow the same discipline as
topics: contact is null while a conversation has not been
analysed and an object with blank fields once it has been analysed and nobody
left a way to be reached, and lead_status is an empty string while the lead
writer has not reached the conversation rather than meaning no lead.
When your leads dataset uses lead identity, each conversation
also names the lead it became: canonical_lead_id is that lead’s permanent UUID
and lead_reference is the same id in the 22-character form a link or a text
message carries. Join on it when you show a lead’s conversations — the email or
phone a visitor typed is only evidence, and the same person can come back with a
different one. Pass either form as canonical_lead_id on the list to read one
lead’s conversations across every widget; it narrows your organization’s
conversations and never reaches anyone else’s. The same filter works on phone
calls and text
conversations. Both fields are empty while the
lead has not been written yet, when the leads dataset is not enrolled in lead
identity, and on conversations recorded before conversations carried the lead’s
identity — those keep empty fields rather than being matched to a lead after the
fact.
From the CLI:
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 a refresh configured on the target dataset that reads recent
conversations and upserts the per-turn latency rows, so you can chart TTFB and
fail-over rate over time. Keep the schedule and source recipe on that dataset’s
refresh configuration rather than creating a second standalone automation for
the same feed. Text and video conversations carry no model metrics, so their
turns array is empty.
Turn a widget on or off from your own system
The Enabled setting is reachable over the REST API and to MCP clients as well as from the dashboard, so a billing system, an onboarding flow, or a scheduled automation can quiet a widget without anyone opening Erdo or editing the site it is embedded on. It is the widget’s counterpart to disabling a lead-capture pipeline: together they stop a page collecting details and stop the assistant asking for them.- Set the status —
POST /v1/voice/widgets/{widget}/statuswith{"status": "disabled"}stops the widget starting conversations, and{"status": "active"}puts it back.{widget}is the widget’s name or public key (vw_…), url-encoded — the same handles the conversation endpoints take. MCP tool:erdo_set_voice_widget_status. Any other word is rejected rather than interpreted, so a mistyped status can never leave a widget serving when you meant to stop it.
Changing a widget’s status needs admin access to the organization, the same
as changing it in the dashboard. A scoped API key needs
resources:write — the same capability that lets it disable a capture pipeline,
because stopping the capture and stopping the assistant that feeds it are two
halves of one decision.
Measure widget activity in Google Analytics
If Erdo has set up a Google Analytics property for your organization — the same property your Erdo-built landing pages report to — your widget sends its activity there automatically. You don’t add a tag or a tracking id: the embed already knows your property, so every conversation shows up in Google Analytics alongside the rest of your site’s traffic.Analytics only flow when Erdo has provisioned a Google Analytics property for
your organization. If your org has no property yet, the first widget load
provisions one automatically — the same way your landing pages do — so there is
nothing to configure.
widget_id, the vw_… value) and its name (widget_name), so you can tell
your widgets apart when you have more than one:
Find widget activity in GA4
Every widget event name starts withvoice_widget_, so in Reports →
Engagement → Events you can filter on that prefix to see just the widget’s
activity, and open any event to break it down by its details — modality to
split voice from chat from video, duration_seconds to see how long calls run,
widget_name to compare widgets. Because these land in your own property, you
report on them exactly like any other event: build an exploration, add them to a
funnel, or chart voice_widget_call_start over time.
Turn widget visitors into a Google Ads audience
The reason the events go to Google Analytics rather than staying inside Erdo is that GA4 is where audiences are built and shared to ads. In Admin → Audiences you can define an audience from any widget event — for example visitors who triggeredvoice_widget_call_start in the last 30 days — and, once your GA4
property is linked to your Google Ads account (Admin → Product links → Google
Ads), that audience becomes available in Google Ads for remarketing. So a
visitor who started a conversation but didn’t convert can be followed up with an
ad, with no extra tag on your site.
The widget deliberately carries no Google Ads tag of its own — everything
flows through your Google Analytics property, and audiences reach Google Ads
through the standard GA4 ↔ Ads link. One property, one place to segment.
Your widget events as an Erdo dataset
The same events also land in a “Widget events” dataset in your Erdo workspace, created automatically the first time your widget loads. Each row is one event with its detail (modality, duration_seconds, the booking form’s
source), the page it happened
on, the visitor’s referrer and campaign parameters (utm_*, gclid), and
enriched dimensions Erdo stamps on arrival — device type, browser, language, and
country. A default Exclude test traffic filter keeps your own testing out of
reports.
Because it’s a regular dataset, you can just ask Erdo about it in chat — “how
many widget conversations did we have last week, by page?”, “average call
duration by campaign?” — chart it on a dashboard, or query it in SQL. On pages
Erdo built for you, widget rows share a session key with the page’s own event
rows, so a single query gives the full journey: page view → widget opened →
conversation → lead. On pages Erdo also runs session analytics, widget events
appear on the same session timeline as the page recording.
Turn analytics off for a page
If you don’t want a particular embed to report anything, adddata-erdo-tracking="off" to the script tag. The widget still works exactly as
before; it just sends no analytics events from that page.
Analytics come from Erdo’s widget embed. A page that embeds a voice provider
directly, rather than through the Erdo snippet, runs none of Erdo’s code and so
sends none of these events.
Match your brand
Set the widget’s accent colour and copy in Agents → Deployments — 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 adata-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.
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:
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.
It switches mid-conversation, too. On a multi-language widget the assistant
detects the language the visitor is actually speaking: start in English, answer in
English; switch to Spanish — or simply ask for Spanish — and the assistant follows,
voice and all, without restarting the conversation. Detection only ever switches
between the languages you configured, so the assistant never wanders into a language
you haven’t given a voice.
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 adata-erdo-voice-* attribute to any element; clicking it
controls the widget (no JavaScript needed):
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
Adddata-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:
Embed it inline as a panel (no floating bubble)
Adddata-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):
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, notacme.comand nothttps://acme.com/contact. - No wildcards.
*.acme.comis not supported. - Matching is exact, and subdomains count as different sites.
https://acme.comdoes not coverhttps://www.acme.comorhttps://shop.acme.com— add each one you actually use, on its own line. - Matching ignores case and a trailing
/.
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, and0
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.
Use your own ElevenLabs account
By default the widget runs on Erdo’s own voice account and each conversation counts against your Erdo credits. If you’d rather run it on your ElevenLabs account — so the usage bills to you and the agents live in a workspace you control — connect ElevenLabs from Data → Connectors and the widget uses it automatically. There is nothing to switch on. There are two ways to connect it, and both work:- Paste an API key. Choose ElevenLabs, paste a key from your ElevenLabs profile, and save.
- Connect the app. Choose the ElevenLabs app and authorize it.
Changing accounts doesn’t move anything. Agents created on Erdo’s account stay
there; a widget built after you connect uses yours. If you disconnect, new
conversations fall back to Erdo’s account and your credits.

