Kyndreddocs

Voice Setup

Enable real-time voice conversations with your companion. Powered by ElevenLabs ConvAI.

How it works

When you configure an ElevenLabs ConvAI agent on a companion, the embed widget automatically enables voice mode. Visitors can switch between text and voice in the chat UI.

  • Real-time voice via WebSocket (low latency)
  • Built-in turn-taking and interruption handling
  • Your API keys stay server-side — embeds use short-lived signed URLs

Setup

1

Create an ElevenLabs ConvAI agent

Go to elevenlabs.io/app/conversational-ai and create a new agent.

Configure:

  • System prompt — the same prompt as your Kyndred companion, or a voice-optimized version
  • Voice — pick a voice from the ElevenLabs library
  • Language — set to your target language (English, Romanian, etc.)
2

Copy the agent ID

In the ElevenLabs dashboard, copy the agent ID (looks like agent_xxxxxxxxxxxx).

3

Paste it into your companion

Go to kyndred.dev/app/companions, open your companion, scroll to the Voice section, paste the agent ID, and save.

4

Test it

Reload the embed. You should see a Talk button on the select screen. Click it, grant mic permission, and start talking.

Mobile WebView requirements

If you're embedding in a mobile app WebView (Flutter, React Native), the native app must grant microphone permission. Browser WebViews won't ask the user automatically.

iOS

Add to Info.plist:

<key>NSMicrophoneUsageDescription</key>
<string>This app uses your microphone for voice conversations.</string>
xml

Android

Add to AndroidManifest.xml:

<uses-permission android:name="android.permission.RECORD_AUDIO" />
xml

Plus handle onPermissionRequest in your WebView to grant the resource.

Custom integration (advanced)

If you're not using our embed widget and want to build a custom voice UI, fetch a signed URL from our API and pass it to the @11labs/client SDK.

import { Conversation } from '@11labs/client';

// 1. Get a signed URL from Kyndred
const res = await fetch(
  'https://kyndred.dev/api/embed/YOUR_TOKEN/voice-token',
  { method: 'POST' }
);
const { agent_id } = await res.json();

// 2. Start ConvAI session
const conv = await Conversation.startSession({
  agentId: agent_id,
  connectionType: 'websocket',
  onConnect: () => console.log('connected'),
  onMessage: ({ message, source }) => console.log(source, message),
  onDisconnect: () => console.log('disconnected'),
});

// Later: end the session
conv.endSession();
js

See the SDK Reference for our provider-agnostic wrapper that lets you swap voice backends without changing your UI code.