How to add a voice assistant to a React app

Add a voice + text agent to a React app in a few minutes (Next.js App Router shown; works in Vite, Remix, CRA too). Want to skip the boilerplate? Let your AI coding assistant set it up — or watch the guide video, our founder doing it in one prompt.

#1. Install

One typed package. React 18 or 19. @latest always pulls the newest release, even if an older version is already installed.

bash
npm install @voxide/react@latest

React is what the widget on this page needs, not what Voxide needs. Vue, Svelte, Angular, Django, Rails and plain HTML run the same client through @voxide/react/core or a script tag, headless and with no prebuilt UI. See Other Frameworks.

#2. Create the assistant

In a Client Component, create a client with your publishable key, then register capabilities, each is a plain-English description, typed params, and a handler that runs your real code. The widget initialises itself, so there's no useEffect or loading flag.

tsx
"use client";
import { VoxideClient, VoxideWidget } from "@voxide/react";
const ai = new VoxideClient({ publicKey: "vox_pub_..." });
ai.register({
addToCart: {
description: "Add an item to the shopping cart.",
params: {
itemId: { type: "string", required: true },
qty: { type: "number" },
},
handler: async ({ itemId, qty = 1 }) => {
await fetch("/api/cart", {
method: "POST",
body: JSON.stringify({ itemId, qty }),
});
return { status: "ok" };
},
},
});
export function Assistant() {
// Pass nothing but the client. Every other prop outranks the dashboard, so
// hardcoding one makes the matching control in Appearance silently do
// nothing. Set the colour, title and placement there instead.
return <VoxideWidget client={ai} />;
}
Leave the look to the dashboard
<VoxideWidget> accepts props for the accent colour, title, position and theme, and every one of them outranks whatever the Appearance tab says. That is deliberate, so a value pinned to a build cannot shift under you, but it means a hardcoded prop makes the matching dashboard control look broken. Pass one only when you want exactly that. From version 0.7.5 the SDK logs a console warning naming any prop that is shadowing a dashboard value.

#3. Mount it once, in the true root

Render the assistant in the component that wraps every route, the root layout, not a page. This is the one step worth double-checking: a call in progress survives navigation and theme changes automatically, but only if the widget itself never unmounts. If it's placed on a specific page (or a nested layout that doesn't cover the whole app), the widget remounts on navigation and any active call gets cut off.

tsx
import { Assistant } from "@/components/Assistant";
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<Assistant />
</body>
</html>
);
}

Vite/CRA: mount it in the top-level <App />, as a sibling of your router. Pages Router: mount it in pages/_app.tsx. Remix/React Router: the root route with the outermost <Outlet />.

Before it works
Whitelist your production domain in the dashboard (project → Settings), localhost always works. Your vox_pub_… key lives in each project's Integration tab (already pre-filled in the copy snippet there).