All posts
3 min readguideswidgetreact

Add a Voice Chat Widget to Your Website

How to put a voice chat widget on your site without building a chat UI: a drop-in component with mic, transcript and text tab that you theme to your brand.

By Voxide

Add a Voice Chat Widget to Your Website

Building a chat UI is a surprising amount of work. Message list, streaming partial transcripts, a microphone permission flow, a waveform that reacts to input level, connection states, error states, mobile keyboard handling, and a launcher that does not fight your z-index. None of it is your product.

This is what a drop-in voice chat widget is for.

The one-line version

import { VoxideClient, VoxideWidget } from "@voxide/react"; const ai = new VoxideClient({ publicKey: "vox_pub_..." }); export default function App() { return <VoxideWidget client={ai} />; }

That renders a launcher in the corner. Opening it gives a panel with two tabs: Voice, which streams microphone audio and plays the reply, and Text, which is an ordinary chat box for people who cannot or would rather not talk.

The widget calls init() for you, shows a connecting state while it loads, and renders a readable error inside the panel if something goes wrong. No useEffect, no loading flag.

Theming it to your brand

<VoxideWidget client={ai} theme="auto" // "light" | "dark" | "auto" accentColor="#FF6600" // your brand colour position="bottom-right" // or "bottom-left" title="Ask Acme" // header label />

Colour, launcher shape and size, greeting text, starter prompts and avatar are also configurable per project from the dashboard, and apply to every embedded widget without a redeploy.

Switching to voice

The Voice tab connects the microphone when the user opens it, and releases it when the panel closes. Visitors are never holding an open mic because they clicked a launcher once — permission is requested at the moment it is needed, which is also the moment it makes sense to the user.

When you want your own UI

If the built-in panel does not fit your design, use the hook and render whatever you like:

import { useVoxideVoice } from "@voxide/react"; function MyMic() { const { status, messages, connect, disconnect, sendText } = useVoxideVoice(ai); return ( <div> <button onClick={status === "connected" ? disconnect : connect}> {status === "connected" ? "Stop" : "Talk"} </button> {messages.map((m, i) => ( <p key={i}>{m.text}</p> ))} </div> ); }

You get the same agent, the same capabilities, and full control of the markup.

A widget that can do things

The important difference from a support-chat bubble: this widget is wired to your application's functions. Register what your app can do and the agent calls it:

ai.register({ bookDemo: { description: "Book a product demo at a given date and time.", params: { name: { type: "string", required: true, sensitive: true }, email: { type: "string", required: true, sensitive: true }, when: { type: "string", required: true }, }, handler: async (args) => crm.createBooking(args), }, });

sensitive: true matters on a public site. If a visitor speaks their name and email into the widget, those values are replaced with [redacted] before the conversation is written to the database — your handler still receives the real values, but they never appear in a transcript, a dashboard, or a backup.

Before it appears for real visitors

Add your production domain to the whitelist in the dashboard. Until you do, the widget shows "Assistant unavailable" on that origin. localhost is always allowed, so this only bites at deploy time — worth doing before you ship, not after.

More on how the key model works in security and CORS, and the whole component API in the documentation.

Keep reading