Website Widget Channel
Embed a voice agent directly into your own website or app. This is the recommended way to expose an agent built on Vois to your customers on the web — no phone number required, and no Vois-hosted page for the customer to leave your site for.
How it works
Every project can have one or more Voice Widget channels, each linked to an agent. A channel has:
- The agent it talks to
- Cosmetic widget settings (color, position, whether the transcript/text chat are shown)
- A public API key (
vois_pk_...), scoped to that channel's agent, used to authenticate the widget from the browser
The public key is safe to embed in client-side code — it identifies which agent/project a request is for, not a secret credential for your account. It can be restricted to specific origins and rate-limited from the Widget API Key panel on the channel.
Setting it up
- Open your project → Channels → Add Channel → Voice Widget.
- Assign the agent this channel should talk to.
- Open the new channel and generate a Widget API Key — the full key is shown once; copy it somewhere safe (only the prefix is shown afterwards).
- Copy the generated embed snippet and paste it into your site.
Integration options
Script tag (recommended)
<script src="https://<your-vois-host>/chat-widget.js" data-public-key="vois_pk_..." async></script>
<script>
window.addEventListener("load", function () {
window.VoisChat.mount({
projectId: "<project id>",
agentId: "<agent id>",
channelId: "<channel id>",
publicKey: "vois_pk_...",
});
});
</script>
Drop this before the closing </body> tag. The widget renders inside a Shadow DOM, so it won't inherit or leak styles from your page.
iframe
If your site's Content Security Policy blocks third-party script injection, embed the same widget in an iframe instead:
<iframe
src="https://<your-vois-host>/api/channels/voice/embed/<channel id>?key=vois_pk_..."
style="position:fixed;bottom:24px;right:24px;width:420px;height:600px;border:none;border-radius:16px;box-shadow:0 8px 32px rgba(0,0,0,.15);z-index:9999"
allow="microphone">
</iframe>
Custom UI / your own app (headless API)
Building your own chat/voice UI (a native mobile app, a design-system-matched web component, etc.) instead of using the widget? You don't need chat-widget.js at all — call the same public API directly:
| Method | Endpoint | Purpose |
|---|---|---|
GET | /widget/v1/config | Project branding + list of available agents |
POST | /widget/v1/session | Launch a session for an agent, returns a provider ephemeral token for WebRTC |
POST | /widget/v1/tools/execute | Execute a tool call mid-session |
POST | /widget/v1/analytics | Report session/tool-call events |
All calls require an X-API-Key: vois_pk_... header (the same key from the channel above). Example:
curl -X POST "https://<your-vois-host>/widget/v1/session" \
-H "X-API-Key: vois_pk_..." \
-H "Content-Type: application/json" \
-d '{"agent_id": 42}'
The response contains a client_secret/ephemeral_token for the agent's configured provider (OpenAI or Gemini) — use it to open your own WebRTC session, following that provider's Realtime/Live API. A packaged client SDK wrapping this session lifecycle is planned; until then this is the supported way to build a fully custom integration.
Origin allowlisting and rate limits
Each widget API key can be restricted to specific origins (allowed_origins, supports *.yourdomain.com wildcards) and given per-minute/per-day rate limits. A request from a non-allowlisted origin is rejected with 401. If your widget isn't connecting, check the browser console for this before assuming an agent misconfiguration.
Gating chat behind a form (Web Form channel, Live Chat mode)
A Web Form channel can run in two modes:
-
Lead Capture — submissions are just stored; nothing continues after submit. Embed the plain form page:
<iframe src="https://<your-vois-host>/api/channels/form/embed/<channel id>"
style="width:100%;max-width:560px;height:520px;border:none" allow="*"></iframe>This is public and needs no API key.
-
Live Chat — the form is a gate: once submitted, the visitor is connected to the channel's assigned agent. This needs the real chat widget (not the plain form page), so the form → chat handoff can happen in one place, and a Widget API Key the same way a Voice Widget channel has one:
<script src="https://<your-vois-host>/chat-widget.js" data-public-key="vois_pk_..." async></script>
<script>
window.addEventListener("load", function () {
window.VoisChat.mount({
projectId: "<project id>",
channelId: "<channel id>",
publicKey: "vois_pk_...",
});
// note: no agentId here — the widget shows the form first and only
// resolves the agent once it's submitted
});
</script>An iframe equivalent is available at
/api/channels/form/embed-widget/<channel id>?key=vois_pk_....Building a custom UI instead?
POST /api/channels/form/submit/<channel id>(public, no key) returns{"mode": "live_chat", "agent_id": ..., "session_id": ...}on success — use thatagent_idwithPOST /widget/v1/session(with the widget key) exactly as described above.
Other ways to reach an agent
- Phone — see Phone Channel for giving an agent a real phone number, with zero web integration.
- WhatsApp — also available as a project channel, for chat-first use cases instead of voice.