How to Add Voice Control to Your Website
A practical guide to adding voice control to a website: expose what your site can already do as functions, then let visitors trigger them by speaking.
By Voxide

Most "voice for your website" tools give you a chatbot that can talk. That is not voice control. Voice control means a visitor says "add two of these to my basket" and the item is actually in their basket — not that a bot replies with instructions on how to click the button themselves.
This guide covers the second kind: wiring speech directly to the functions your site already has.
What voice control actually requires
Three things have to be true before a visitor can drive your site by speaking:
- The agent has to know what your site can do. Not what it says — what it can execute.
- The agent has to know what the user is currently looking at, or "add that one" is meaningless.
- The agent has to be able to run your code, in the browser, with the user's session.
Traditional chatbot builders solve none of these. They match phrases to canned replies. You end up maintaining a dialog tree that goes stale the moment you ship a feature.
Step 1 — Install the SDK
npm install @voxide/react@latest
One typed package. Works with React 18 or 19, in Next.js, Vite, Remix or CRA.
Step 2 — Describe what your site can do
This is the part that replaces the dialog tree. You register your real JavaScript functions with a plain-English description and typed parameters:
"use client";
import { VoxideClient, VoxideWidget } from "@voxide/react";
const ai = new VoxideClient({ publicKey: "vox_pub_..." });
ai.register({
searchProducts: {
description: "Search the catalogue by free-text query.",
params: { query: { type: "string", required: true } },
handler: async ({ query }) => {
const res = await fetch(`/api/search?q=${encodeURIComponent(query)}`);
return res.json();
},
},
addToCart: {
description: "Add an item to the shopping cart.",
params: {
itemId: { type: "string", required: true },
qty: { type: "number" },
},
handler: async ({ itemId, qty = 1 }) => {
await cart.add(itemId, qty);
return { status: "added", total: cart.count };
},
},
});
There is no intent list and no training phrases. The model reads the descriptions and decides which function fits what the visitor said. Add a new capability and it can be used immediately.
Note that searchProducts returns its results. Whatever a handler returns is fed back to the model, so the agent can answer "yes, three left in medium" out loud instead of guessing.
Step 3 — Let the agent see the current page
"Add that one to my cart" only works if the agent knows what "that one" is:
ai.bindState(() => ({
currentPage: location.pathname,
visibleProducts: getVisibleProducts(),
cart: cart.items,
}));
Your getter runs on every turn, so the agent always reasons over the live UI rather than a stale snapshot. This is covered in more depth in state awareness.
Step 4 — Drop in the widget
export default function App() {
return <VoxideWidget client={ai} accentColor="#FF6600" />;
}
A launcher appears in the corner with a voice tab and a text tab. Mount it once, in the component that wraps every route — a root layout, not a page. If the widget unmounts on navigation, an in-progress call gets cut off.
Step 5 — Guard the destructive stuff
Voice input is fuzzy. Anything irreversible should confirm first:
ai.register({
cancelOrder: {
description: "Cancel an order that has not shipped.",
params: { orderId: { type: "string", required: true } },
dangerous: true, // asks the user to confirm before running
handler: async ({ orderId }) => api.cancel(orderId),
},
});
You can replace the default browser confirm with your own modal via ai.onConfirmation().
Before it works: whitelist your domain
The SDK runs in your visitors' browsers, so the publishable key is locked to origins you approve in the dashboard. localhost always works, so local development needs no setup. See security and CORS for why a publishable key is safe to ship in a bundle.
Where teams usually start
Pick the three things visitors do most and register those first. Voice earns its place fastest where clicking is slowest — long forms, nested filters, dense dashboards, and any flow that needs both hands.
If you are on Next.js specifically, the router wiring has a few extra details worth reading: add voice to a Next.js app.
