Skip to main content

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

  1. Open your project → ChannelsAdd ChannelVoice Widget.
  2. Assign the agent this channel should talk to.
  3. 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).
  4. Copy the generated embed snippet and paste it into your site.

Integration options

<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:

MethodEndpointPurpose
GET/widget/v1/configProject branding + list of available agents
POST/widget/v1/sessionLaunch a session for an agent, returns a provider ephemeral token for WebRTC
POST/widget/v1/tools/executeExecute a tool call mid-session
POST/widget/v1/analyticsReport 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 that agent_id with POST /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.