npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@voxide/react

v0.8.0

Published

Capability-first voice AI SDK for the web. Register your JavaScript functions and let a live voice agent call them when users speak or type.

Readme

@voxide/react

Capability-first voice AI for any website. Describe what your app can do as plain JavaScript functions, and a live voice agent decides when and how to call them from what your users say or type — no intents, no dialog trees, no string matching.

npm install @voxide/react@latest

Ships fully-typed React components (React 18 or 19). Works in Next.js, Vite, CRA, Remix — anything that renders React in the browser.


60-second quick start

"use client";
import { VoxideClient, VoxideWidget } from "@voxide/react";

// 1. Create a client with your publishable key (from the Voxide dashboard).
const ai = new VoxideClient({ publicKey: "vox_pub_..." });

// 2. Tell the agent what your app can do.
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" };
    },
  },
});

// 3. Drop the widget in. It initialises itself — no useEffect, no loading flag.
export default function App() {
  return <VoxideWidget client={ai} />;
}

That's it. A launcher appears in the corner. <VoxideWidget> calls ai.init() for you, shows a "Connecting…" state while it loads, and a clear error inside the panel if something goes wrong.


Core concepts

  • Capability-first — you register what your app can do; the model matches intent to capability. Add a function, and the agent can use it immediately.
  • Hosted backend — the SDK talks only to the Voxide backend. Your publishable key is safe to ship in the browser; it never touches Google directly.
  • Manifest sync — on init() the SDK uploads a snapshot of your registered actions so you can inspect, version, and lock them from the dashboard.
  • Live stateai.bindState(() => ({ cart, page })) lets the agent always see the current UI without you stuffing prompts.
  • Real results — whatever your handler returns is fed back to the model, so a checkStock tool can answer "yes, 3 left" out loud.

Before it works: allow your domain

The SDK runs in your users' browsers and calls the Voxide backend cross-origin.

  1. Open your project in the Voxide dashboard.
  2. Add the domain(s) where you embed the widget to the domain whitelist (e.g. app.yoursite.com).
  3. localhost is always allowed, so local dev needs no setup.

If a domain isn't whitelisted, the widget shows "Assistant unavailable" and the console logs a domain/CORS error.


The widget

<VoxideWidget
  client={ai}
  theme="auto"            // "light" | "dark" | "auto" (default: auto)
  accentColor="#FF6600"   // your brand colour
  position="bottom-right" // or "bottom-left"
  title="Ask Acme"        // header label (defaults to the agent name)
/>

The panel has a Text and a Voice tab. Voice streams mic audio to the agent and plays its reply; text is a normal chat box. Switching to Voice auto-connects the mic; closing the panel releases it.

Prefer your own UI? Use the hook:

import { useVoxideVoice } from "@voxide/react";

function MyMic() {
  const { status, messages, connect, disconnect, sendText } = useVoxideVoice(ai);
  // ...render whatever you like
}

API

new VoxideClient(config)

| option | type | notes | |---|---|---| | publicKey | string | required — your vox_pub_... key. | | baseUrl | string | Override the Voxide backend (self-hosting). You normally omit this. | | language | string | ISO code, e.g. "en-US". | | ui | VoxideUIConfig | Default widget look: accentColor, position, theme, title. |

ai.register(actions)

ai.register({
  bookTable: {
    description: "Reserve a table.",
    params: { guests: { type: "number", required: true }, time: { type: "string", required: true } },
    scope: "global",        // or a route prefix like "/restaurant" (or "/shop/*")
    dangerous: false,        // if true, the user is asked to confirm first
    handler: async (args) => { /* ... */ },
  },
});

Protecting personal data — sensitive: true

If a visitor speaks their name, phone number or address to fill a form, that value would otherwise be stored with the conversation. Mark the parameter sensitive and Voxide replaces it with [redacted] before writing it to the database — so it is never visible in your dashboard, never visible to Voxide, and not present in any backup.

ai.register({
  fillContactForm: {
    description: "Fill in the contact form.",
    params: {
      name:  { type: "string", sensitive: true },
      phone: { type: "string", sensitive: true },
      topic: { type: "string" },
    },
    // Your handler still receives the real values — only storage is affected.
    handler: async ({ name, phone, topic }) => submitForm({ name, phone, topic }),
  },
});

Emails, phone numbers, card numbers, national IDs and IBANs are already detected and removed from transcripts automatically. Pattern matching can't reliably recognise a spoken name or street address, which is exactly what sensitive: true is for. Redaction is permanent and cannot be undone.

ai.bindState(getter)

Expose current UI state to the agent every turn:

ai.bindState(() => ({ cart: getCart(), currentPage: location.pathname }));

ai.setActiveRoute(path)

Scope which actions are callable on the current page. Actions with scope: "/checkout" only surface there; "/shop/*" matches any sub-route.

ai.setUser({ userId, email })

Identify the end-user so memory can persist across sessions.

ai.use((ctx, next, cancel) => ...)

Middleware for validation, logging, rate-limiting, or blocking a call. cancel() stops execution.

ai.onConfirmation(handler)

Replace the default window.confirm for dangerous actions with your own modal:

ai.onConfirmation(async (action, args) => myModal.confirm(action.description));

ai.enableNavigation(router, routes?)

Auto-registers a navigate action wired to your router (Next.js useRouter, React Router, etc.).

Pass your real routes. Without them the agent has to guess a path from what the user said, so "take me to the near-me page" becomes /nearMe when your route is /near — a 404. Given the list, the model is constrained to your exact paths, and an off-list path is refused instead of navigating to a dead page.

ai.enableNavigation(router, [
  { path: "/near",  description: "Spots near the user" },
  { path: "/saved", description: "The user's saved spots" },
]);
// shorthand:
ai.enableNavigation(router, { "/near": "Spots near me", "/saved": "Saved spots" });

ai.on(event, cb)

Subscribe to "action" | "status" | "message" | "transcript" | "ready" | "error". Returns an unsubscribe function.

ai.init()

Optional — <VoxideWidget> calls it for you. Idempotent and safe to call multiple times. Call it manually only if you want to initialise before the widget mounts.


TypeScript

Everything is typed. Import helper types directly:

import type { VoxideAction, VoxideStatus, VoxideUIConfig } from "@voxide/react";

License

MIT © Voxide