Ultravox Voice Widget

A drop-in browser voice agent — floating mic launcher, live streaming transcripts, shadow-DOM isolated. One script tag, any site.

~508 KB minified Shadow DOM Web Components ESM · CJS · IIFE
The widget on this page will try to mint a call against /api/voice/mint — this static host doesn't have one, so clicking Start here will surface a mint error. Wire the widget into a page where you've stood up that route to see it talk.

Drop-in install

<script>
  window.UltravoxWidget = {
    mintUrl: "/api/voice/mint",
    title: "Site helper",
    callOptions: { voice: "Mark", maxDurationSeconds: 600 }
  };
</script>
<script src="https://THIS-DEPLOY-URL/voice-widget.js" defer></script>

Programmatic

<script src="https://THIS-DEPLOY-URL/voice-widget.js"></script>
<script>
  const w = UltravoxWidget.mount({
    mintUrl: "/api/voice/mint",
    onTranscript: (m) => console.log(m.who, m.text),
  });
</script>

Mint endpoint (your server)

The widget never sees your Ultravox API key. Your server trades it for a short-lived joinUrl:

// POST /api/voice/mint
const r = await fetch("https://api.ultravox.ai/api/calls", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-Key": process.env.ULTRAVOX_API_KEY,
  },
  body: JSON.stringify({
    systemPrompt: body.systemPrompt ?? "You are a helpful site assistant.",
    model: "fixie-ai/ultravox",
    voice: body.voice ?? "Mark",
    languageHint: "en",
    temperature: 0.4,
    maxDuration: `${Math.min(3600, body.maxDurationSeconds ?? 600)}s`,
    firstSpeaker: "FIRST_SPEAKER_AGENT",
    medium: { webRtc: {} },
  }),
});
res.status(r.ok ? 200 : 502).json(await r.json());

Try it

Look bottom-right of this page. The launcher is mounted; click it, hit Start. (Expect a mint error on this static host — see the note above.)