Pinecall

Props

Every prop the VoiceWidget accepts — including multi-language and metadata.

All props#

PropTypeDefaultDescription
agentstringrequiredAgent ID to connect to
serverstring"https://voice.pinecall.io"Pinecall API base URL (override for self-hosted)
namestring"Agent"Display name shown in status label during calls
labelstring"Talk to {name}"Tooltip shown on hover when idle
presetVoiceWidgetPreset"dark"Theme preset (dark, midnight, aurora, sunset, light)
themePartial<VoiceWidgetTheme>Custom theme overrides, merged on top of preset
configRecord<string, unknown>Session config overrides (voice, STT, language, greeting)
metadataRecord<string, unknown>Metadata passed to the agent (available as call.metadata)
languagesRecord<string, LanguagePreset>Multi-language presets (see below)
defaultLanguagestringfirst keyInitial language selection
onLanguageChange(lang, preset) => voidCalled when the user picks a language
trackedToolsstring[]Tool names to track in widget state for UI rendering (see Tools API)
classNamestringExtra CSS class on the root wrapper
onStatusChange(status) => voidCalled when connection status changes

config — session overrides#

Pass session-level overrides to the agent. Same shortcut syntax as @pinecall/sdk:

<VoiceWidget
  agent="mara"
  config={{
    voice: "elevenlabs:EXAVITQu4vr4xnSDxMaL",
    stt: { provider: "deepgram", model: "nova-3", language: "es" },
    language: "es",
    greeting: "¡Hola! ¿En qué puedo ayudarte?",
  }}
/>

See STT Providers and TTS Providers for the full shortcut formats.

metadata — server-side context#

Whatever you pass shows up as call.metadata in your agent. Use it to attach user IDs, session IDs, A/B test variants, anything you want the server to know about this specific call.

<VoiceWidget
  agent="mara"
  metadata={{
    userId: currentUser.id,
    plan: currentUser.plan,
    experimentVariant: "B",
  }}
/>

On the server:

agent.on("call.started", (call) => {
  console.log("Call from user", call.metadata.userId);
});

languages — multi-language selector#

Enables a language pill bar that appears on hover and stays visible during calls. Each language preset configures the voice, STT, turn detection, and greeting for that language.

import { VoiceWidget } from "@pinecall/voice-widget";
import type { LanguagePreset } from "@pinecall/voice-widget";

const LANGUAGES: Record<string, LanguagePreset> = {
  en: {
    label: "English",
    flag: "🇬🇧",
    voice: "elevenlabs:EXAVITQu4vr4xnSDxMaL",
    stt: "deepgram-flux",
    language: "en",
    greeting: "Hello! How can I help you?",
  },
  es: {
    label: "Español",
    flag: "🇪🇸",
    voice: "elevenlabs:h2cd3gvcqTp3m65Dysk7",
    stt: { provider: "deepgram", model: "nova-3", language: "es" },
    language: "es",
    greeting: "¡Hola! ¿En qué puedo ayudarte?",
  },
  ar: {
    label: "العربية",
    flag: "🇸🇦",
    voice: "elevenlabs:jAAHNNqlbAX9iWjJPEtE",
    stt: { provider: "deepgram", model: "nova-3", language: "ar" },
    language: "ar",
    turnDetection: "smart_turn",
    greeting: "مرحباً، كيف يمكنني مساعدتك؟",
  },
};

<VoiceWidget
  agent="mara"
  name="Mara"
  languages={LANGUAGES}
  defaultLanguage="en"
  onLanguageChange={(lang, preset) => console.log(`Switched to ${lang}`)}
/>;

LanguagePreset shape#

FieldTypeDescription
labelstringDisplay name (e.g. "Español")
flagstringFlag emoji (e.g. "🇪🇸")
voicestringVoice ID in provider:id format
sttstring | objectSTT shortcut ("deepgram-flux") or full config
languagestringLanguage code for STT ("es", "ar", etc.)
turnDetectionstring | objectTurn detection mode ("smart_turn", "native") or full config
greetingstringCustom greeting spoken when the call starts

Behavior#

  • Pre-call: Pill bar appears on hover. Selecting a language updates the session config for the next connect().
  • Mid-call: Pills stay visible. Selecting a language sends a configure message via DataChannel — voice, STT, and turn detection hot-swap without disconnecting.
  • Greeting: Only applies at call start (sent in the offer body). Mid-call language changes don't re-trigger the greeting.

onStatusChange — observability#

<VoiceWidget
  agent="mara"
  onStatusChange={(status) => {
    if (status === "connected") analytics.track("call_started");
    if (status === "idle") analytics.track("call_ended");
    if (status === "error") analytics.track("call_error");
  }}
/>

trackedTools — interactive tool UI#

Tells the widget which tool calls to expose in widget state for UI rendering. Untracked tools are handled silently by the server-side agent.

<VoiceWidget
  agent="booking-demo"
  trackedTools={["getAvailableSlots", "showContactForm"]}
>
  <ToolPanel />
</VoiceWidget>

See Tools API for the full pattern.

What's next#