home / skills / jezweb / claude-skills / elevenlabs-agents
This skill helps you configure and troubleshoot ElevenLabs voice agents with RAG knowledge bases, tool integration, and secure deployment.
npx playbooks add skill jezweb/claude-skills --skill elevenlabs-agentsReview the files below or copy the command above to add this skill to your agents.
---
name: elevenlabs-agents
description: |
Build conversational AI voice agents with ElevenLabs Platform. Configure agents, tools, RAG knowledge bases, agent versioning with A/B testing, and MCP security. React, React Native, or Swift SDKs. Prevents 34 documented errors.
Use when: building voice agents, AI phone systems, agent versioning/branching, MCP security, or troubleshooting @11labs deprecated, webhook errors, CSP violations, localhost allowlist, tool parsing errors.
user-invocable: true
---
# ElevenLabs Agents Platform
## Overview
ElevenLabs Agents Platform is a comprehensive solution for building production-ready conversational AI voice agents. The platform coordinates four core components:
1. **ASR (Automatic Speech Recognition)** - Converts speech to text (32+ languages, sub-second latency)
2. **LLM (Large Language Model)** - Reasoning and response generation (GPT, Claude, Gemini, custom models)
3. **TTS (Text-to-Speech)** - Converts text to speech (5000+ voices, 31 languages, low latency)
4. **Turn-Taking Model** - Proprietary model that handles conversation timing and interruptions
### π¨ Package Updates (January 2026)
ElevenLabs migrated to new scoped packages in August 2025. **Current packages:**
```bash
npm install @elevenlabs/[email protected] # React SDK (Dec 2025: localization, Scribe fixes)
npm install @elevenlabs/[email protected] # JavaScript SDK (Dec 2025: localization)
npm install @elevenlabs/[email protected] # React Native SDK (Dec 2025: mic fixes, speed param)
npm install @elevenlabs/[email protected] # Base SDK (Jan 2026: latest)
npm install -g @elevenlabs/[email protected] # CLI
```
**DEPRECATED:** `@11labs/react`, `@11labs/client` (uninstall if present)
**β οΈ CRITICAL:** v1 TTS models were removed on 2025-12-15. Use Turbo v2/v2.5 only.
### December 2025 Updates
**Widget Improvements (v0.5.5)**:
- Microphone permission handling improvements (better UX for permission requests)
- Text-only mode (`chat_mode: true`) no longer requires microphone access
- `end_call` system tool fix (no longer omits last message)
**SDK Fixes**:
- Scribe audio format parameter now correctly transmitted (v2.32.0, Jan 2026)
- React Native infinite loop fix in useEffect dependencies (v0.5.6)
- Speed parameter support in TTS overrides (v0.5.7)
- Localization support for chat UI terms (v0.12.3)
---
## Package Selection Guide
**Which ElevenLabs package should I use?**
| Package | Environment | Use Case |
|---------|-------------|----------|
| `@elevenlabs/elevenlabs-js` | **Server only** (Node.js) | Full API access, TTS, voices, models |
| `@elevenlabs/client` | **Browser + Server** | Agents SDK, WebSocket, lightweight |
| `@elevenlabs/react` | **React apps** | Conversational AI hooks |
| `@elevenlabs/react-native` | **Mobile** | iOS/Android agents |
**β οΈ Why elevenlabs-js doesn't work in browser:**
- Depends on Node.js `child_process` module (by design)
- **Error**: `Module not found: Can't resolve 'child_process'`
- **Workaround for browser API access**: Create proxy server endpoint using `elevenlabs-js`, call proxy from browser
**Affected Frameworks:**
- Next.js client components
- Vite browser builds
- Electron renderer process
- Tauri webview
**Source**: [GitHub Issue #293](https://github.com/elevenlabs/elevenlabs-js/issues/293)
---
## 1. Quick Start
### React SDK
```bash
npm install @elevenlabs/react zod
```
```typescript
import { useConversation } from '@elevenlabs/react';
const { startConversation, stopConversation, status } = useConversation({
agentId: 'your-agent-id',
signedUrl: '/api/elevenlabs/auth', // Recommended (secure)
// OR apiKey: process.env.NEXT_PUBLIC_ELEVENLABS_API_KEY,
clientTools: { /* browser-side tools */ },
onEvent: (event) => { /* transcript, agent_response, tool_call */ },
serverLocation: 'us' // 'eu-residency' | 'in-residency' | 'global'
});
```
### CLI ("Agents as Code")
```bash
npm install -g @elevenlabs/agents-cli
elevenlabs auth login
elevenlabs agents init # Creates agents.json, tools.json, tests.json
elevenlabs agents add "Bot" --template customer-service
elevenlabs agents push --env dev # Deploy
elevenlabs agents test "Bot" # Test
```
### API (Programmatic)
```typescript
import { ElevenLabsClient } from 'elevenlabs';
const client = new ElevenLabsClient({ apiKey: process.env.ELEVENLABS_API_KEY });
const agent = await client.agents.create({
name: 'Support Bot',
conversation_config: {
agent: { prompt: { prompt: "...", llm: "gpt-4o" }, language: "en" },
tts: { model_id: "eleven_turbo_v2_5", voice_id: "your-voice-id" }
}
});
```
---
## 2. SDK Parameter Naming (camelCase vs snake_case)
**CRITICAL**: The JS SDK uses **camelCase** for parameters while the Python SDK and API use **snake_case**. Using snake_case in JS causes silent failures where parameters are ignored.
**Common Parameters:**
| API/Python (snake_case) | JS SDK (camelCase) |
|-------------------------|-------------------|
| `model_id` | `modelId` |
| `voice_id` | `voiceId` |
| `output_format` | `outputFormat` |
| `voice_settings` | `voiceSettings` |
**Example:**
```typescript
// β WRONG - parameter ignored (snake_case):
const stream = await elevenlabs.textToSpeech.convert(voiceId, {
model_id: "eleven_v3", // Silently ignored!
text: "Hello"
});
// β
CORRECT - use camelCase:
const stream = await elevenlabs.textToSpeech.convert(voiceId, {
modelId: "eleven_v3", // Works!
text: "Hello"
});
```
**Tip**: Always check TypeScript types for correct parameter names. This is the most common error when migrating from Python SDK.
**Source**: [GitHub Issue #300](https://github.com/elevenlabs/elevenlabs-js/issues/300)
---
## 3. Agent Configuration
### System Prompt Architecture (6 Components)
**1. Personality** - Identity, role, character traits
**2. Environment** - Communication context (phone, web, video)
**3. Tone** - Formality, speech patterns, verbosity
**4. Goal** - Objectives and success criteria
**5. Guardrails** - Boundaries, prohibited topics, ethical constraints
**6. Tools** - Available capabilities and when to use them
**Template:**
```json
{
"agent": {
"prompt": {
"prompt": "Personality:\n[Agent identity and role]\n\nEnvironment:\n[Communication context]\n\nTone:\n[Speech style]\n\nGoal:\n[Primary objectives]\n\nGuardrails:\n[Boundaries and constraints]\n\nTools:\n[Available tools and usage]",
"llm": "gpt-4o", // gpt-5.1, claude-sonnet-4-5, gemini-3-pro-preview
"temperature": 0.7
}
}
}
```
**2025 LLM Models:**
- `gpt-5.1`, `gpt-5.1-2025-11-13` (Oct 2025)
- `claude-sonnet-4-5`, `claude-sonnet-4-5@20250929` (Oct 2025)
- `gemini-3-pro-preview` (2025)
- `gemini-2.5-flash-preview-09-2025` (Oct 2025)
### Turn-Taking Modes
| Mode | Behavior | Best For |
|------|----------|----------|
| **Eager** | Responds quickly | Fast-paced support, quick orders |
| **Normal** | Balanced (default) | General customer service |
| **Patient** | Waits longer | Information collection, therapy |
```json
{ "conversation_config": { "turn": { "mode": "patient" } } }
```
### Workflows & Agent Management (2025)
**Workflow Features:**
- **Subagent Nodes** - Override prompt, voice, turn-taking per node
- **Tool Nodes** - Guarantee tool execution
- **Edges** - Conditional routing with `edge_order` (determinism, Oct 2025)
```json
{
"workflow": {
"nodes": [
{ "id": "node_1", "type": "subagent", "config": { "system_prompt": "...", "turn_eagerness": "patient" } },
{ "id": "node_2", "type": "tool", "tool_name": "transfer_to_human" }
],
"edges": [{ "from": "node_1", "to": "node_2", "condition": "escalation", "edge_order": 1 }]
}
}
```
**Agent Management (2025):**
- **Agent Archiving** - `archived: true` field (Oct 2025)
- **Agent Duplication** - Clone existing agents
- **Service Account API Keys** - Management endpoints (Jul 2025)
### Dynamic Variables
Use `{{var_name}}` syntax in prompts, messages, and tool parameters.
**System Variables:**
- `{{system__agent_id}}`, `{{system__conversation_id}}`
- `{{system__caller_id}}`, `{{system__called_number}}` (telephony)
- `{{system__call_duration_secs}}`, `{{system__time_utc}}`
- `{{system__call_sid}}` (Twilio only)
**Custom Variables:**
```typescript
await client.conversations.create({
agent_id: "agent_123",
dynamic_variables: { user_name: "John", account_tier: "premium" }
});
```
**Secret Variables:** `{{secret__api_key}}` (headers only, never sent to LLM)
**β οΈ Error:** Missing variables cause "Missing required dynamic variables" - always provide all referenced variables.
---
## 3. Voice & Language Features
### Multi-Voice, Pronunciation & Speed
**Multi-Voice** - Switch voices dynamically (adds ~200ms latency per switch):
```json
{ "prompt": "When speaking as customer, use voice_id 'voice_abc'. As agent, use 'voice_def'." }
```
**Pronunciation Dictionary** - IPA, CMU, word substitutions (Turbo v2/v2.5 only):
```json
{
"pronunciation_dictionary": [
{ "word": "API", "pronunciation": "ey-pee-ay", "format": "cmu" },
{ "word": "AI", "substitution": "artificial intelligence" }
]
}
```
**PATCH Support (Aug 2025)** - Update dictionaries without replacement
**Speed Control** - 0.7x-1.2x (use 0.9x-1.1x for natural sound):
```json
{ "voice_settings": { "speed": 1.0 } }
```
**Voice Cloning Best Practices:**
- Clean audio (no noise, music, pops)
- Consistent microphone distance
- 1-2 minutes of audio
- Use language-matched voices (English voices fail on non-English)
### Language Configuration
**32+ Languages** with automatic detection and in-conversation switching.
**Multi-Language Presets:**
```json
{
"language_presets": [
{ "language": "en", "voice_id": "en_voice", "first_message": "Hello!" },
{ "language": "es", "voice_id": "es_voice", "first_message": "Β‘Hola!" }
]
}
```
---
## 4. Knowledge Base & RAG
Enable agents to access large knowledge bases without loading entire documents into context.
**Workflow:**
1. Upload documents (PDF, TXT, DOCX)
2. Compute RAG index (vector embeddings)
3. Agent retrieves relevant chunks during conversation
**Configuration:**
```json
{
"agent": { "prompt": { "knowledge_base": ["doc_id_1", "doc_id_2"] } },
"knowledge_base_config": {
"max_chunks": 5,
"vector_distance_threshold": 0.8
}
}
```
**API Upload:**
```typescript
const doc = await client.knowledgeBase.upload({ file: fs.createReadStream('docs.pdf'), name: 'Docs' });
await client.knowledgeBase.computeRagIndex({ document_id: doc.id, embedding_model: 'e5_mistral_7b' });
```
**β οΈ Gotchas:** RAG adds ~500ms latency. Check index status before use - indexing can take minutes.
---
## 5. Tools (4 Types)
### β οΈ BREAKING CHANGE: prompt.tools Deprecated (July 2025)
The legacy `prompt.tools` array was **removed on July 23, 2025**. All agent configurations must use the new format.
**Migration Timeline:**
- July 14, 2025: Legacy format still accepted
- July 15, 2025: GET responses stop including `tools` field
- **July 23, 2025**: POST/PATCH reject `prompt.tools` (active now)
**Old Format** (no longer works):
```typescript
{
agent: {
prompt: {
tools: [{ name: "get_weather", url: "...", method: "GET" }]
}
}
}
```
**New Format** (required):
```typescript
{
agent: {
prompt: {
tool_ids: ["tool_abc123"], // Client/server tools
built_in_tools: ["end_call"] // System tools (new field)
}
}
}
```
**Error if both used**: "A request must include either prompt.tool_ids or the legacy prompt.tools array β never both"
**Note**: All tools from legacy format were auto-migrated to standalone tool records.
**Source**: [Official Migration Guide](https://elevenlabs.io/docs/agents-platform/customization/tools/agent-tools-deprecation)
---
### A. Client Tools (Browser/Mobile)
Execute in browser or mobile app. **Tool names case-sensitive.**
```typescript
clientTools: {
updateCart: {
description: "Update shopping cart",
parameters: z.object({ item: z.string(), quantity: z.number() }),
handler: async ({ item, quantity }) => {
// Client-side logic
return { success: true };
}
}
}
```
### B. Server Tools (Webhooks)
HTTP requests to external APIs. **PUT support added Apr 2025.**
```json
{
"name": "get_weather",
"url": "https://api.weather.com/{{user_id}}",
"method": "GET",
"headers": { "Authorization": "Bearer {{secret__api_key}}" },
"parameters": { "type": "object", "properties": { "city": { "type": "string" } } }
}
```
**β οΈ Secret variables** only in headers (not URL/body)
**2025 Features:**
- **transfer-to-human** system tool (Apr 2025)
- **tool_latency_secs** tracking (Apr 2025)
**β οΈ Historical Issue (Fixed Feb 2025):**
Tool calling was broken with `gpt-4o-mini` due to an OpenAI API change. This was fixed in SDK v2.25.0+ (Feb 17, 2025). If using older SDK versions, upgrade to avoid silent tool execution failures on that model.
**Source**: [Changelog Feb 17, 2025](https://elevenlabs.io/docs/changelog/2025/2/17)
### C. MCP Tools (Model Context Protocol)
Connect to MCP servers for databases, IDEs, data sources.
**Configuration:** Dashboard β Add Custom MCP Server β Configure SSE/HTTP endpoint
**Approval Modes:** Always Ask | Fine-Grained | No Approval
**2025 Updates:**
- **disable_interruptions** flag (Oct 2025) - Prevents interruption during tool execution
- **Tools Management Interface** (Jun 2025)
**β οΈ Limitations:** SSE/HTTP only. Not available for Zero Retention or HIPAA.
### D. System Tools
Built-in conversation control (no external APIs):
- `end_call`, `detect_language`, `transfer_agent`
- `transfer_to_number` (telephony)
- `dtmf_playpad`, `voicemail_detection` (telephony)
**2025:** `use_out_of_band_dtmf` flag for telephony integration
---
## 6. SDK Integration
### useConversation Hook (React/React Native)
```typescript
const { startConversation, stopConversation, status, isSpeaking } = useConversation({
agentId: 'your-agent-id',
signedUrl: '/api/auth', // OR apiKey: process.env.NEXT_PUBLIC_ELEVENLABS_API_KEY
clientTools: { /* ... */ },
onEvent: (event) => { /* transcript, agent_response, tool_call, agent_tool_request (Oct 2025) */ },
onConnect/onDisconnect/onError,
serverLocation: 'us' // 'eu-residency' | 'in-residency' | 'global'
});
```
**2025 Events:**
- `agent_chat_response_part` - Streaming responses (Oct 2025)
- `agent_tool_request` - Tool interaction tracking (Oct 2025)
### Connection Types: WebRTC vs WebSocket
| Feature | WebSocket | WebRTC (Jul 2025 rollout) |
|---------|-----------|---------------------------|
| **Auth** | `signedUrl` | `conversationToken` |
| **Audio** | Configurable (16k/24k/48k) | PCM_48000 (hardcoded) |
| **Latency** | Standard | Lower |
| **Best For** | Flexibility | Low-latency |
**β οΈ WebRTC:** Hardcoded PCM_48000, limited device switching
### Platforms
- **React**: `@elevenlabs/[email protected]`
- **JavaScript**: `@elevenlabs/[email protected]` - `new Conversation({...})`
- **React Native**: `@elevenlabs/[email protected]` - Expo SDK 47+, iOS/macOS (custom build required, no Expo Go)
- **Swift**: iOS 14.0+, macOS 11.0+, Swift 5.9+
- **Embeddable Widget**: `<script src="https://elevenlabs.io/convai-widget/index.js"></script>`
- **Widget Packages** (Dec 2025):
- `@elevenlabs/[email protected]` - For embedding in existing apps
- `@elevenlabs/[email protected]` - Core widget functionality
### Scribe (Real-Time Speech-to-Text - Beta 2025)
Real-time transcription with word-level timestamps. **Single-use tokens**, not API keys.
```typescript
const { connect, startRecording, stopRecording, transcript, partialTranscript } = useScribe({
token: async () => (await fetch('/api/scribe/token')).json().then(d => d.token),
commitStrategy: 'vad', // 'vad' (auto on silence) | 'manual' (explicit .commit())
sampleRate: 16000, // 16000 or 24000
onPartialTranscript/onFinalTranscript/onError
});
```
**Events:** PARTIAL_TRANSCRIPT, FINAL_TRANSCRIPT_WITH_TIMESTAMPS, SESSION_STARTED, ERROR
**β οΈ Closed Beta** - requires sales contact. For agents, use Agents Platform instead (LLM + TTS + two-way interaction).
**β οΈ Webhook Mode Issue:**
Using `speechToText.convert()` with `webhook: true` causes SDK parsing errors. The API returns only `{ request_id }` for webhook mode, but the SDK expects the full transcription schema.
**Error Message:**
```
ParseError: response: Missing required key "language_code"; Missing required key "text"; ...
```
**Workaround** - Use direct fetch API instead of SDK:
```typescript
const formData = new FormData();
formData.append('file', audioFile);
formData.append('model_id', 'scribe_v1');
formData.append('webhook', 'true');
formData.append('webhook_id', webhookId);
const response = await fetch('https://api.elevenlabs.io/v1/speech-to-text', {
method: 'POST',
headers: { 'xi-api-key': apiKey },
body: formData,
});
const result = await response.json(); // { request_id: 'xxx' }
// Actual transcription delivered to webhook endpoint
```
**Source**: [GitHub Issue #232](https://github.com/elevenlabs/elevenlabs-js/issues/232) (confirmed by maintainer)
---
## 7. Testing & Evaluation
### π Agent Testing Framework (Aug 2025)
Comprehensive automated testing with **9 new API endpoints** for creating, managing, and executing tests.
**Test Types:**
- **Scenario Testing** - LLM-based evaluation against success criteria
- **Tool Call Testing** - Verify correct tool usage and parameters
- **Load Testing** - High-concurrency capacity testing
**CLI Workflow:**
```bash
# Create test
elevenlabs tests add "Refund Test" --template basic-llm
# Configure in test_configs/refund-test.json
{
"name": "Refund Test",
"scenario": "Customer requests refund",
"success_criteria": ["Agent acknowledges empathetically", "Verifies order details"],
"expected_tool_call": { "tool_name": "lookup_order", "parameters": { "order_id": "..." } }
}
# Deploy and execute
elevenlabs tests push
elevenlabs agents test "Support Agent"
```
**9 New API Endpoints (Aug 2025):**
1. `POST /v1/convai/tests` - Create test
2. `GET /v1/convai/tests/:id` - Retrieve test
3. `PATCH /v1/convai/tests/:id` - Update test
4. `DELETE /v1/convai/tests/:id` - Delete test
5. `POST /v1/convai/tests/:id/execute` - Execute test
6. `GET /v1/convai/test-invocations` - List invocations (pagination, agent filtering)
7. `POST /v1/convai/test-invocations/:id/resubmit` - Resubmit failed test
8. `GET /v1/convai/test-results/:id` - Get results
9. `GET /v1/convai/test-results/:id/debug` - Detailed debugging info
**Test Invocation Listing (Oct 2025):**
```typescript
const invocations = await client.convai.testInvocations.list({
agent_id: 'agent_123', // Filter by agent
page_size: 30, // Default 30, max 100
cursor: 'next_page_cursor' // Pagination
});
// Returns: test run counts, pass/fail stats, titles
```
**Programmatic Testing:**
```typescript
const simulation = await client.agents.simulate({
agent_id: 'agent_123',
scenario: 'Refund request',
user_messages: ["I want a refund", "Order #12345"],
success_criteria: ["Acknowledges request", "Verifies order"]
});
console.log('Passed:', simulation.passed);
```
**Agent Tracking (Oct 2025):** Tests now include `agent_id` association for better organization
---
## 8. Analytics & Monitoring
**2025 Features:**
- **Custom Dashboard Charts** (Apr 2025) - Display evaluation criteria metrics over time
- **Call History Filtering** (Apr 2025) - `call_start_before_unix` parameter
- **Multi-Voice History** - Separate conversation history by voice
- **LLM Cost Tracking** - Per agent/conversation costs with `aggregation_interval` (hour/day/week/month)
- **Tool Latency** (Apr 2025) - `tool_latency_secs` tracking
- **Usage Metrics** - minutes_used, request_count, ttfb_avg, ttfb_p95
**Conversation Analysis:** Success evaluation (LLM-based), data collection fields, post-call webhooks
**Access:** Dashboard β Analytics | Post-call Webhooks | API
---
## 9. Privacy & Compliance
**Data Retention:** 2 years default (GDPR). Configure: `{ "transcripts": { "retention_days": 730 }, "audio": { "retention_days": 2190 } }`
**Encryption:** TLS 1.3 (transit), AES-256 (rest)
**Regional:** `serverLocation: 'eu-residency' | 'us' | 'global' | 'in-residency'`
**Zero Retention Mode:** Immediate deletion (no history, analytics, webhooks, or MCP)
**Compliance:** GDPR (1-2 years), HIPAA (6 years), SOC 2 (automatic encryption)
---
## 10. Cost Optimization
**LLM Caching:** Up to 90% savings on repeated inputs. `{ "caching": { "enabled": true, "ttl_seconds": 3600 } }`
**Model Swapping:** GPT-5.1, GPT-4o/mini, Claude Sonnet 4.5, Gemini 3 Pro/2.5 Flash (2025 models)
**Burst Pricing:** 3x concurrency limit at 2x cost. `{ "burst_pricing_enabled": true }`
---
## 11. Advanced Features
**2025 Platform Updates:**
- **Azure OpenAI** (Jul 2025) - Custom LLM with Azure-hosted models (requires API version field)
- **Genesys Output Variables** (Jul 2025) - Enhanced call analytics
- **LLMReasoningEffort "none"** (Oct 2025) - Control model reasoning behavior
- **Streaming Voice Previews** (Jul 2025) - Real-time voice generation
- **pcm_48000** audio format (Apr 2025) - New output format support
**Events:** `audio`, `transcript`, `agent_response`, `tool_call`, `agent_chat_response_part` (streaming, Oct 2025), `agent_tool_request` (Oct 2025), `conversation_state`
**Custom Models:** Bring your own LLM (OpenAI-compatible endpoints). `{ "llm_config": { "custom": { "endpoint": "...", "api_key": "{{secret__key}}" } } }`
**Post-Call Webhooks:** HMAC verification required. Return 200 or auto-disable after 10 failures. Payload includes conversation_id, transcript, analysis.
**Chat Mode:** Text-only (no ASR/TTS). `{ "chat_mode": true }`. Saves ~200ms + costs.
**Telephony:** SIP (sip-static.rtc.elevenlabs.io), Twilio native, Vonage, RingCentral. **2025:** Twilio keypad fix (Jul), SIP TLS remote_domains validation (Oct)
---
## 12. CLI & DevOps ("Agents as Code")
**Installation & Auth:**
```bash
npm install -g @elevenlabs/[email protected]
elevenlabs auth login
elevenlabs auth residency eu-residency # 'in-residency' | 'global'
export ELEVENLABS_API_KEY=your-api-key # For CI/CD
```
**Project Structure:** `agents.json`, `tools.json`, `tests.json` + `agent_configs/`, `tool_configs/`, `test_configs/`
**Key Commands:**
```bash
elevenlabs agents init
elevenlabs agents add "Bot" --template customer-service
elevenlabs agents push --env prod --dry-run # Preview
elevenlabs agents push --env prod # Deploy
elevenlabs agents pull # Import existing
elevenlabs agents test "Bot" # 2025: Enhanced testing
elevenlabs tools add-webhook "Weather" --config-path tool_configs/weather.json
elevenlabs tools push
elevenlabs tests add "Test" --template basic-llm
elevenlabs tests push
```
**Multi-Environment:** Create `agent.dev.json`, `agent.staging.json`, `agent.prod.json` for overrides
**CI/CD:** GitHub Actions with `--dry-run` validation before deploy
**.gitignore:** `.env`, `.elevenlabs/`, `*.secret.json`
---
## 13. Common Errors & Solutions (27 Documented)
### Error 1: Missing Required Dynamic Variables
**Cause:** Variables referenced in prompts not provided at conversation start
**Solution:** Provide all variables in `dynamic_variables: { user_name: "John", ... }`
### Error 2: Case-Sensitive Tool Names
**Cause:** Tool name mismatch (case-sensitive)
**Solution:** Ensure `tool_ids: ["orderLookup"]` matches `name: "orderLookup"` exactly
### Error 3: Webhook Authentication Failures
**Cause:** Incorrect HMAC signature, not returning 200, or 10+ failures
**Solution:** Verify `hmac = crypto.createHmac('sha256', SECRET).update(payload).digest('hex')` and return 200
**β οΈ Header Name:** Use `ElevenLabs-Signature` (NOT `X-ElevenLabs-Signature` - no X- prefix!)
### Error 4: Voice Consistency Issues
**Cause:** Background noise, inconsistent mic distance, extreme volumes in training
**Solution:** Use clean audio, consistent distance, avoid extremes
### Error 5: Wrong Language Voice
**Cause:** English-trained voice for non-English language
**Solution:** Use language-matched voices: `{ "language": "es", "voice_id": "spanish_voice" }`
### Error 6: Restricted API Keys Not Supported (CLI)
**Cause:** CLI doesn't support restricted API keys
**Solution:** Use unrestricted API key for CLI
### Error 7: Agent Configuration Push Conflicts
**Cause:** Hash-based change detection missed modification
**Solution:** `elevenlabs agents init --override` + `elevenlabs agents pull` + push
### Error 8: Tool Parameter Schema Mismatch
**Cause:** Schema doesn't match usage
**Solution:** Add clear descriptions: `"description": "Order ID (format: ORD-12345)"`
### Error 9: RAG Index Not Ready
**Cause:** Index still computing (takes minutes)
**Solution:** Check `index.status === 'ready'` before using
### Error 10: WebSocket Protocol Error (1002)
**Cause:** Network instability, incompatible browser, or firewall issues
**Symptoms:**
```
Error receiving message: received 1002 (protocol error)
Error sending user audio chunk: received 1002 (protocol error)
WebSocket is already in CLOSING or CLOSED state
```
Connection cycles: Disconnected β Connected β Disconnected rapidly
**Solution:**
1. **Use WebRTC instead of WebSocket** for better stability: `connectionType: 'webrtc'`
2. **Implement reconnection logic** with exponential backoff
3. **Check network stability** and firewall rules (port restrictions)
4. **Test on different networks/browsers** to isolate the issue
**Source**: [GitHub Issue #134](https://github.com/elevenlabs/elevenlabs-examples/issues/134)
### Error 11: 401 Unauthorized in Production
**Cause:** Agent visibility or API key config
**Solution:** Check visibility (public/private), verify API key in prod, check allowlist
### Error 12: Allowlist Connection Errors
**Cause:** Allowlist enabled but using shared link, OR localhost validation bug
**Symptoms:**
```
Host is not supported
Host is not valid or supported
Host is not in insights whitelist
WebSocket is already in CLOSING or CLOSED state
```
**Solution:**
1. Configure allowlist domains in dashboard or disable for testing
2. **Localhost workaround**: Use `127.0.0.1:3000` instead of `localhost:3000`
**β οΈ Localhost Validation Bug:**
The dashboard has inconsistent validation for localhost URLs:
- β `localhost:3000` β Rejected (should be valid)
- β `http://localhost:3000` β Rejected (protocol not allowed)
- β `localhost:3000/voice-chat` β Rejected (paths not allowed)
- β
`www.localhost:3000` β Accepted (invalid but accepted!)
- β
`127.0.0.1:3000` β Accepted (use this for local dev)
**Source**: [GitHub Issue #320](https://github.com/elevenlabs/elevenlabs-js/issues/320)
### Error 13: Workflow Infinite Loops
**Cause:** Edge conditions creating loops
**Solution:** Add max iteration limits, test all paths, explicit exit conditions
### Error 14: Burst Pricing Not Enabled
**Cause:** Burst not enabled in settings
**Solution:** `{ "call_limits": { "burst_pricing_enabled": true } }`
### Error 15: MCP Server Timeout
**Cause:** MCP server slow/unreachable
**Solution:** Check URL accessible, verify transport (SSE/HTTP), check auth, monitor logs
### Error 16: First Message Cutoff on Android
**Cause:** Android needs time to switch audio mode
**Solution:** `connectionDelay: { android: 3_000, ios: 0 }` (3s for audio routing)
### Error 17: CSP (Content Security Policy) Violations
**Cause:** Strict CSP blocks `blob:` URLs. SDK uses Audio Worklets loaded as blobs
**Solution:** Self-host worklets:
1. `cp node_modules/@elevenlabs/client/dist/worklets/*.js public/elevenlabs/`
2. Configure: `workletPaths: { 'rawAudioProcessor': '/elevenlabs/rawAudioProcessor.worklet.js', 'audioConcatProcessor': '/elevenlabs/audioConcatProcessor.worklet.js' }`
3. Update CSP: `script-src 'self' https://elevenlabs.io; worker-src 'self';`
**Gotcha:** Update worklets when upgrading `@elevenlabs/client`
### Error 18: Webhook Payload - Null Message on Tool Calls
**Cause:** Schema expects `message: string` but ElevenLabs sends `null` when agent makes tool calls
**Solution:** Use `z.string().nullable()` for message field in Zod schemas
```typescript
// β Fails on tool call turns:
message: z.string()
// β
Correct:
message: z.string().nullable()
```
**Real payload example:**
```json
{ "role": "agent", "message": null, "tool_calls": [{ "tool_name": "my_tool", ... }] }
```
### Error 19: Webhook Payload - call_successful is String, Not Boolean
**Cause:** Schema expects `call_successful: boolean` but ElevenLabs sends `"success"` or `"failure"` strings
**Solution:** Accept both types and convert for database storage
```typescript
// Schema:
call_successful: z.union([z.boolean(), z.string()]).optional()
// Conversion helper:
function parseCallSuccessful(value: unknown): boolean | undefined {
if (value === undefined || value === null) return undefined
if (typeof value === 'boolean') return value
if (typeof value === 'string') return value.toLowerCase() === 'success'
return undefined
}
```
### Error 20: Webhook Schema Validation Fails Silently
**Cause:** Real ElevenLabs payloads have many undocumented fields that strict schemas reject
**Undocumented fields in transcript turns:**
- `agent_metadata`, `multivoice_message`, `llm_override`, `rag_retrieval_info`
- `llm_usage`, `interrupted`, `original_message`, `source_medium`
**Solution:** Add all as `.optional()` with `z.any()` for fields you don't process
**Debugging tip:** Use https://webhook.site to capture real payloads, then test schema locally
### Error 21: Webhook Cost Field is Credits, NOT USD
**Cause:** `metadata.cost` contains **ElevenLabs credits**, not USD dollars. Displaying this directly shows wildly wrong values (e.g., "$78.0000" when actual cost is ~$0.003)
**Solution:** Extract actual USD from `metadata.charging.llm_price` instead
```typescript
// β Wrong - displays credits as dollars:
cost: metadata?.cost // Returns 78 (credits)
// β
Correct - actual USD cost:
const charging = metadata?.charging as any
cost: charging?.llm_price ?? null // Returns 0.0036 (USD)
```
**Real payload structure:**
```json
{
"metadata": {
"cost": 78, // β CREDITS, not dollars!
"charging": {
"llm_price": 0.0036188999999999995, // β Actual USD cost
"llm_charge": 18, // LLM credits
"call_charge": 60, // Audio credits
"tier": "pro"
}
}
}
```
**Note:** `llm_price` only covers LLM costs. Audio costs may require separate calculation based on your plan.
### Error 22: User Context Available But Not Extracted
**Cause:** Webhook contains authenticated user info from widget but code doesn't extract it
**Solution:** Extract `dynamic_variables` from `conversation_initiation_client_data`
```typescript
const dynamicVars = data.conversation_initiation_client_data?.dynamic_variables
const callerName = dynamicVars?.user_name || null
const callerEmail = dynamicVars?.user_email || null
const currentPage = dynamicVars?.current_page || null
```
**Payload example:**
```json
{
"conversation_initiation_client_data": {
"dynamic_variables": {
"user_name": "Jeremy Dawes",
"user_email": "[email protected]",
"current_page": "/dashboard/calls"
}
}
}
```
### Error 23: Data Collection Results Available But Not Displayed
**Cause:** ElevenLabs agents can collect structured data during calls (configured in agent settings). This data is stored in `analysis.data_collection_results` but often not parsed/displayed in UI.
**Solution:** Parse the JSON and display collected fields with their values and rationales
```typescript
const dataCollectionResults = analysis?.dataCollectionResults
? JSON.parse(analysis.dataCollectionResults)
: null
// Display each collected field:
Object.entries(dataCollectionResults).forEach(([key, data]) => {
console.log(`${key}: ${data.value} (${data.rationale})`)
})
```
**Payload example:**
```json
{
"data_collection_results": {
"customer_name": { "value": "John Smith", "rationale": "Customer stated their name" },
"intent": { "value": "billing_inquiry", "rationale": "Asking about invoice" },
"callback_number": { "value": "+61400123456", "rationale": "Provided for callback" }
}
}
```
### Error 24: Evaluation Criteria Results Available But Not Displayed
**Cause:** Custom success criteria (configured in agent) produce results in `analysis.evaluation_criteria_results` but often not parsed/displayed
**Solution:** Parse and show pass/fail status with rationales
```typescript
const evaluationResults = analysis?.evaluationCriteriaResults
? JSON.parse(analysis.evaluationCriteriaResults)
: null
Object.entries(evaluationResults).forEach(([key, data]) => {
const passed = data.result === 'success' || data.result === true
console.log(`${key}: ${passed ? 'PASS' : 'FAIL'} - ${data.rationale}`)
})
```
**Payload example:**
```json
{
"evaluation_criteria_results": {
"verified_identity": { "result": "success", "rationale": "Customer verified DOB" },
"resolved_issue": { "result": "failure", "rationale": "Escalated to human" }
}
}
```
### Error 25: Feedback Rating Available But Not Extracted
**Cause:** User can provide thumbs up/down feedback. Stored in `metadata.feedback.thumb_rating` but not extracted
**Solution:** Extract and store the rating (1 = thumbs up, -1 = thumbs down)
```typescript
const feedback = metadata?.feedback as any
const feedbackRating = feedback?.thumb_rating ?? null // 1, -1, or null
// Also available:
const likes = feedback?.likes // Array of things user liked
const dislikes = feedback?.dislikes // Array of things user disliked
```
**Payload example:**
```json
{
"metadata": {
"feedback": {
"thumb_rating": 1,
"likes": ["helpful", "natural"],
"dislikes": []
}
}
}
```
### Error 26: Per-Turn Metadata Not Extracted (interrupted, source_medium, rag_retrieval_info)
**Cause:** Each transcript turn has valuable metadata that's often ignored
**Solution:** Store these fields per message for analytics and debugging
```typescript
const turnAny = turn as any
const messageData = {
// ... existing fields
interrupted: turnAny.interrupted ?? null, // Was turn cut off by user?
sourceMedium: turnAny.source_medium ?? null, // Channel: web, phone, etc.
originalMessage: turnAny.original_message ?? null, // Pre-processed message
ragRetrievalInfo: turnAny.rag_retrieval_info // What knowledge was retrieved
? JSON.stringify(turnAny.rag_retrieval_info)
: null,
}
```
**Use cases:**
- `interrupted: true` β User spoke over agent (UX insight)
- `source_medium` β Analytics by channel
- `rag_retrieval_info` β Debug/improve knowledge base retrieval
### Error 27: Upcoming Audio Flags (August 2025)
**Cause:** Three new boolean fields coming in August 2025 webhooks that may break schemas
**Solution:** Add these fields to schemas now (as optional) to be ready
```typescript
// In webhook payload (coming August 15, 2025):
has_audio: boolean // Was full audio recorded?
has_user_audio: boolean // Was user audio captured?
has_response_audio: boolean // Was agent audio captured?
// Schema (future-proof):
const schema = z.object({
// ... existing fields
has_audio: z.boolean().optional(),
has_user_audio: z.boolean().optional(),
has_response_audio: z.boolean().optional(),
})
```
**Note:** These match the existing fields in the GET Conversation API response
### Error 28: Tool Parsing Fails When Tool Not Found
**Cause:** Calling `conversations.get(id)` when conversation contains tool_results where the tool was deleted/not found
**Error Message:**
```
Error: response -> transcript -> [11] -> tool_results -> [0] -> type:
Expected string. Received null.;
response -> transcript -> [11] -> tool_results -> [0] -> type:
[Variant 1] Expected "system". Received null.;
response -> transcript -> [11] -> tool_results -> [0] -> type:
[Variant 2] Expected "workflow". Received null.
```
**Solution:**
1. **SDK fix needed** - SDK should handle null tool_results.type gracefully
2. **Workaround for users:**
- Ensure all referenced tools exist before deleting them
- Wrap `conversation.get()` in try-catch until SDK is fixed
```typescript
try {
const conversation = await client.conversationalAi.conversations.get(id);
} catch (error) {
console.error('Tool parsing error - conversation may reference deleted tools');
}
```
**Source**: [GitHub Issue #268](https://github.com/elevenlabs/elevenlabs-js/issues/268)
### Error 29: SDK Parameter Naming Confusion (snake_case vs camelCase)
**Cause:** Using snake_case parameters (from API/Python SDK docs) in JS SDK, which expects camelCase
**Symptoms:** Parameters silently ignored, wrong model/voice used, no error messages
**Common Mistakes:**
```typescript
// β WRONG - parameter ignored:
convert(voiceId, { model_id: "eleven_v3" })
// β
CORRECT:
convert(voiceId, { modelId: "eleven_v3" })
```
**Solution:** Always use camelCase for JS SDK parameters. Check TypeScript types if unsure.
**Affected Parameters:** `model_id`, `voice_id`, `output_format`, `voice_settings`, and all API parameters
**Source**: [GitHub Issue #300](https://github.com/elevenlabs/elevenlabs-js/issues/300)
### Error 30: Webhook Mode ParseError with speechToText.convert()
**Cause:** SDK expects full transcription response but webhook mode returns only `{ request_id }`
**Error Message:**
```
ParseError: Missing required key "language_code"; Missing required key "text"; ...
```
**Solution:** Use direct fetch API instead of SDK for webhook mode:
```typescript
const formData = new FormData();
formData.append('file', audioFile);
formData.append('model_id', 'scribe_v1');
formData.append('webhook', 'true');
formData.append('webhook_id', webhookId);
const response = await fetch('https://api.elevenlabs.io/v1/speech-to-text', {
method: 'POST',
headers: { 'xi-api-key': apiKey },
body: formData,
});
const result = await response.json(); // { request_id: 'xxx' }
```
**Source**: [GitHub Issue #232](https://github.com/elevenlabs/elevenlabs-js/issues/232)
### Error 31: Package Not Compatible with Browser/Web
**Cause:** Using `@elevenlabs/elevenlabs-js` in browser/client environments (depends on Node.js `child_process`)
**Error Message:**
```
Module not found: Can't resolve 'child_process'
```
**Affected Frameworks:**
- Next.js client components
- Vite browser builds
- Electron renderer process
- Tauri webview
**Solution:**
1. **For browser/web**: Use `@elevenlabs/client` or `@elevenlabs/react` instead
2. **For full API access in browser**: Create proxy server endpoint using `elevenlabs-js`, call from browser
3. **For Electron/Tauri**: Use `elevenlabs-js` in main process only, not renderer
**Note:** This is by design - `elevenlabs-js` is server-only
**Source**: [GitHub Issue #293](https://github.com/elevenlabs/elevenlabs-js/issues/293)
### Error 32: prompt.tools Deprecated - POST/PATCH Rejected
**Cause:** Using legacy `prompt.tools` array field after July 23, 2025 cutoff
**Error Message:**
```
A request must include either prompt.tool_ids or the legacy prompt.tools array β never both
```
**Solution:** Migrate to new format:
```typescript
// β Old (rejected):
{ agent: { prompt: { tools: [...] } } }
// β
New (required):
{
agent: {
prompt: {
tool_ids: ["tool_abc123"], // Client/server tools
built_in_tools: ["end_call"] // System tools
}
}
}
```
**Note:** All legacy tools were auto-migrated to standalone records. Just update your configuration references.
**Source**: [Official Migration Guide](https://elevenlabs.io/docs/agents-platform/customization/tools/agent-tools-deprecation)
### Error 33: GPT-4o Mini Tool Calling Broken (Fixed Feb 2025)
**Cause:** OpenAI API breaking change affected `gpt-4o-mini` tool execution (historical issue)
**Symptoms:** Tools silently fail to execute, no error messages
**Solution:** Upgrade to SDK v2.25.0+ (released Feb 17, 2025). If using older SDK versions, upgrade or avoid `gpt-4o-mini` for tool-based workflows.
**Source**: [Changelog Feb 17, 2025](https://elevenlabs.io/docs/changelog/2025/2/17)
### Error 34: Scribe Audio Format Parameter Not Transmitted (Fixed v2.32.0)
**Cause:** WebSocket URI wasn't including `audio_format` parameter even when specified (historical issue)
**Solution:** Upgrade to `@elevenlabs/[email protected]` or later (released Jan 19, 2026)
**Source**: [GitHub PR #319](https://github.com/elevenlabs/elevenlabs-js/pull/319)
---
## 14. Agent Versioning (Jan 2026)
ElevenLabs introduced Agent Versioning in January 2026, enabling git-like version control for conversational AI agents. This allows safe experimentation, A/B testing, and gradual rollouts.
### Core Concepts
| Concept | ID Format | Description |
|---------|-----------|-------------|
| **Version** | `agtvrsn_xxxx` | Immutable snapshot of agent config at a point in time |
| **Branch** | `agtbrch_xxxx` | Isolated development path (like git branches) |
| **Draft** | Per-user/branch | Work-in-progress changes before committing |
| **Deployment** | Traffic splits | A/B testing with percentage-based routing |
### Enabling Versioning
```typescript
// Enable versioning on existing agent
const agent = await client.conversationalAi.agents.update({
agentId: 'your-agent-id',
enableVersioningIfNotEnabled: true
});
```
**β οΈ Note:** Once enabled, versioning cannot be disabled on an agent.
### Branch Management
```typescript
// Create a new branch for experimentation
const branch = await client.conversationalAi.agents.branches.create({
agentId: 'your-agent-id',
parentVersionId: 'agtvrsn_xxxx', // Branch from this version
name: 'experiment-v2'
});
// List all branches
const branches = await client.conversationalAi.agents.branches.list({
agentId: 'your-agent-id'
});
// Delete a branch (must not have active traffic)
await client.conversationalAi.agents.branches.delete({
agentId: 'your-agent-id',
branchId: 'agtbrch_xxxx'
});
```
### Traffic Deployment (A/B Testing)
Route traffic between branches using percentage splits:
```typescript
// Deploy 90/10 traffic split
const deployment = await client.conversationalAi.agents.deployments.create({
agentId: 'your-agent-id',
deployments: [
{ branchId: 'agtbrch_main', percentage: 90 },
{ branchId: 'agtbrch_xxxx', percentage: 10 }
]
});
// Get current deployment status
const status = await client.conversationalAi.agents.deployments.get({
agentId: 'your-agent-id'
});
```
**Use Cases:**
- **A/B Testing** - Test new prompts on 10% of traffic before full rollout
- **Gradual Rollouts** - Increase traffic incrementally (10% β 25% β 50% β 100%)
- **Quick Rollback** - Route 100% back to stable branch if issues detected
### Merging Branches
```typescript
// Merge successful experiment back to main
const merge = await client.conversationalAi.agents.branches.merge({
agentId: 'your-agent-id',
sourceBranchId: 'agtbrch_xxxx',
targetBranchId: 'agtbrch_main',
archiveSourceBranch: true // Clean up after merge
});
```
### Working with Drafts
Drafts are per-user, per-branch work-in-progress states:
```typescript
// Get current draft
const draft = await client.conversationalAi.agents.drafts.get({
agentId: 'your-agent-id',
branchId: 'agtbrch_xxxx'
});
// Update draft (changes not yet committed)
await client.conversationalAi.agents.drafts.update({
agentId: 'your-agent-id',
branchId: 'agtbrch_xxxx',
conversationConfig: {
agent: { prompt: { prompt: 'Updated system prompt...' } }
}
});
// Commit draft to create new version
const version = await client.conversationalAi.agents.drafts.commit({
agentId: 'your-agent-id',
branchId: 'agtbrch_xxxx',
message: 'Improved greeting flow'
});
```
### Best Practices
1. **Always test on branch first** - Never experiment directly on production traffic
2. **Use descriptive branch names** - `feature-multilang`, `fix-timeout-handling`
3. **Start with small traffic splits** - Begin at 5-10%, monitor metrics, then increase
4. **Archive merged branches** - Keep repository clean
5. **Commit messages** - Use clear messages for version history
**Source**: [Agent Versioning Docs](https://elevenlabs.io/docs/agents-platform/customization/personalization/agent-versioning)
---
## 15. MCP Security & Guardrails
When connecting MCP (Model Context Protocol) servers to ElevenLabs agents, security is critical. MCP tools can access databases, APIs, and sensitive data.
### Tool Approval Modes
| Mode | Behavior | Use When |
|------|----------|----------|
| **Always Ask** | Explicit approval for every tool execution | Default - recommended for most cases |
| **Fine-Grained** | Auto-approve trusted ops, require approval for sensitive | Established, trusted MCP servers |
| **No Approval** | All tool executions auto-approved | Only thoroughly vetted, internal servers |
**Configuration:**
```typescript
{
"mcp_config": {
"server_url": "https://your-mcp-server.com",
"approval_mode": "always_ask", // 'always_ask' | 'fine_grained' | 'no_approval'
"fine_grained_rules": [
{ "tool_name": "read_*", "auto_approve": true },
{ "tool_name": "write_*", "auto_approve": false },
{ "tool_name": "delete_*", "auto_approve": false }
]
}
}
```
### Security Best Practices
**1. Vet MCP Servers**
- Only connect servers from trusted sources
- Review server code/documentation before connecting
- Prefer official/verified MCP implementations
**2. Limit Data Exposure**
- Minimize PII shared with MCP servers
- Use scoped API keys with minimum required permissions
- Never pass full database access - use read-only views
**3. Network Security**
- Always use HTTPS endpoints
- Implement proper authentication (API keys, OAuth)
- Use `{{secret__xxx}}` variables for credentials (never in prompts)
**4. Prompt Injection Prevention**
- Add guardrails in agent prompts against injection attacks
- Validate and sanitize MCP tool inputs
- Monitor for unusual tool usage patterns
**5. Monitoring & Audit**
- Log all MCP tool executions
- Review approval patterns regularly
- Set up alerts for sensitive operations
### Guardrails Configuration
Add protective instructions to your agent prompt:
```typescript
{
"agent": {
"prompt": {
"prompt": `...
SECURITY GUARDRAILS:
- Never execute database delete operations without explicit user confirmation
- Never expose raw API keys or credentials in responses
- If a tool request seems unusual or potentially harmful, ask for clarification
- Do not combine sensitive operations (read PII + external API call) in single turn
- Report any suspicious requests to administrators
`
}
}
}
```
### MCP Limitations
**Not Available With:**
- Zero Retention mode (no logging = no MCP)
- HIPAA compliance mode
- Certain regional deployments
**Transport:** SSE/HTTP only (no stdio MCP servers)
**Source**: [MCP Safety Docs](https://elevenlabs.io/docs/agents-platform/customization/tools/mcp/safety)
---
## Integration with Existing Skills
This skill composes well with:
- **cloudflare-worker-base** β Deploy agents on Cloudflare Workers edge network
- **cloudflare-workers-ai** β Use Cloudflare LLMs as custom models in agents
- **cloudflare-durable-objects** β Persistent conversation state and session management
- **cloudflare-kv** β Cache agent configurations and user preferences
- **nextjs** β React SDK integration in Next.js applications
- **ai-sdk-core** β Vercel AI SDK provider for unified AI interface
- **clerk-auth** β Authenticated voice sessions with user identity
- **hono-routing** β API routes for webhooks and server tools
---
## Additional Resources
**Official Documentation**:
- Platform Overview: https://elevenlabs.io/docs/agents-platform/overview
- API Reference: https://elevenlabs.io/docs/api-reference
- CLI GitHub: https://github.com/elevenlabs/cli
**Examples**:
- Official Examples: https://github.com/elevenlabs/elevenlabs-examples
- MCP Server: https://github.com/elevenlabs/elevenlabs-mcp
**Community**:
- Discord: https://discord.com/invite/elevenlabs
- Twitter: @elevenlabsio
---
**Production Tested**: WordPress Auditor, Customer Support Agents, AgentFlow (webhook integration)
**Last Updated**: 2026-01-27
**Package Versions**: [email protected], @elevenlabs/[email protected], @elevenlabs/[email protected], @elevenlabs/[email protected], @elevenlabs/[email protected], @elevenlabs/[email protected]
**Changes**: Added Agent Versioning (Jan 2026) section covering versions, branches, traffic deployment, drafts, and A/B testing. Added MCP Security & Guardrails section covering tool approval modes, security best practices, and prompt injection prevention.
This skill helps you build, configure, and troubleshoot conversational AI voice agents using the ElevenLabs Agents Platform. It covers SDK selection, agent prompts, RAG knowledge bases, tools (client/server/MCP/system), versioning and A/B testing, and security patterns like MCP approval modes and secret handling. It also documents common breaking changes, package migrations, and 34 documented errors to prevent.
The skill inspects agent configuration, SDK usage, and runtime integration points to validate correct parameter names, tool formats, and dynamic variable usage. It guides selection of the correct ElevenLabs packages per environment, ensures TTS/ASR/turn-taking settings are valid, and surfaces known gotchas (deprecated fields, removed models, browser-only issues). It also outlines workflows for RAG indexing, voice management, and tool execution paths (client, server, MCP, system).
Which package should I install for browser-based agents?
Use @elevenlabs/client or @elevenlabs/react for browser; elevenlabs-js is server-only and will fail in browser builds.
Why are some parameters ignored at runtime?
In JS/TS use camelCase parameter names; passing snake_case (API/Python style) will be silently ignored by the JS SDK.
What replaced prompt.tools?
The legacy prompt.tools array was removed; use prompt.tool_ids for custom tools and built_in_tools for system tools.