elevenlabs/skills · Official

agents

Build voice AI agents with ElevenLabs. Use when creating voice assistants, customer service bots, interactive voice characters, or any real-time voice conversation experience, and when configuring an agent's tools, workflows, or procedures, including creating, editing, compiling, and publishing procedure drafts on an agent branch over the SDKs or REST API.

All-time #2075 Trending #1915 First seen Jan 28, 2026
8-week activity · all time api

Installation

$ npx skills add elevenlabs/skills --skill agents

Summary

  • Build voice AI agents with ElevenLabs.
  • Use when creating voice assistants, customer service bots, interactive voice characters, or any real-time voice conversation experience, and when configuring an agent's tools, workflows, or procedures, including creating, editing, compiling, and publishing procedure drafts on an agent branch over the SDKs or REST API.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from elevenlabs/skills · top by installs.

npx skills add elevenlabs/skills

Browse all from elevenlabs/skills

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Declared
Cline Not declared
OpenCode Not declared

Repository health

Stars 443
License LICENSE
Default branch main
Open issues 2
Status Active

Skill metadata

Parsed from SKILL.md frontmatter.

LicenseMIT
CompatibilityRequires internet access and an ElevenLabs API key (ELEVENLABS_API_KEY).
Declared agents gemini clawdbot

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 24,594 B
  • docs SUMMARY.md 372 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 7,500 installs

SKILL.md

ElevenLabs Agents Platform

Build voice AI agents with natural conversations, multiple LLM providers, custom tools, and easy web embedding.

Setup: See [Installation Guide](references/installation.md) for CLI and SDK setup.

Quick Start with CLI

The ElevenLabs CLI is the recommended way to create and manage agents:

# Install CLI and authenticate
npm install -g @elevenlabs/cli
elevenlabs auth login

# Initialize project and create an agent
elevenlabs agents init
elevenlabs agents add "My Assistant" --template complete

# Push to ElevenLabs platform
elevenlabs agents push

Available templates: complete, minimal, voice-only, text-only, customer-service, assistant

Python

from elevenlabs import ElevenLabs

client = ElevenLabs()

agent = client.conversational_ai.agents.create(
    name="My Assistant",
    conversation_config={
        "agent": {
            "first_message": "Hello! How can I help?",
            "language": "en",
            "prompt": {
                "prompt": "You are a helpful assistant. Be concise and friendly.",
                "llm": "gemini-2.0-flash",
                "temperature": 0.7
            }
        },
        "tts": {"voice_id": "JBFqnCBsd6RMkjVDRZzb"}
    }
)

JavaScript

import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
const client = new ElevenLabsClient();

const agent = await client.conversationalAi.agents.create({
  name: "My Assistant",
  conversationConfig: {
    agent: {
      firstMessage: "Hello! How can I help?",
      language: "en",
      prompt: {
        prompt: "You are a helpful assistant.",
        llm: "gemini-2.0-flash",
        temperature: 0.7
      }
    },
    tts: { voiceId: "JBFqnCBsd6RMkjVDRZzb" }
  }
});

CLI

The CLI reads ELEVENLABSAPIKEY from the environment automatically:

elevenlabs agents create \
  --json '{"name": "My Assistant", "conversation_config": {"agent": {"first_message": "Hello!", "language": "en", "prompt": {"prompt": "You are helpful.", "llm": "gemini-2.0-flash"}}, "tts": {"voice_id": "JBFqnCBsd6RMkjVDRZzb"}}}'

Starting Conversations

Authenticated WebRTC: Request a session token from your backend. The response includes both the token and the conversation ID:

session = client.conversational_ai.conversations.get_webrtc_token(
    agent_id="your-agent-id",
)
print(session.token, session.conversation_id)

Server-side (Python): Get signed URL for client connection:

signed_url = client.conversational_ai.conversations.get_signed_url(
    agent_id="your-agent-id",
    environment="staging",
)

Client-side (JavaScript):

import { Conversation } from "@elevenlabs/client";

const conversation = await Conversation.startSession({
  agentId: "your-agent-id",
  environment: "staging",
  overrides: { asr: { keywords: ["ElevenLabs", "TechCorp"] } },
  onMessage: (msg) => console.log("Agent:", msg.message),
  onUserTranscript: (t) => console.log("User:", t.message),
  onPing: (event) => console.log("Estimated latency:", event.ping_ms),
  onContextUsage: ({ model, context_tokens, context_limit_tokens }) =>
    console.log(`${model}: ${context_tokens}/${context_limit_tokens} context tokens`),
  onError: (e) => console.error(e)
});

React Hook: Wrap hook consumers in ConversationProvider. Prefer granular hooks such as useConversationControls and useConversationStatus for session controls and UI state; useConversation remains available as the convenience all-in-one hook. Pass provider-level callbacks such as onError when you want React to handle conversation errors in one place.

import {
  ConversationProvider,
  useConversationControls,
  useConversationStatus,
} from "@elevenlabs/react";

function Agent({ signedUrl }: { signedUrl: string }) {
  const { startSession, endSession } = useConversationControls();
  const { status } = useConversationStatus();

  if (status === "connected") {
    return <button onClick={endSession}>End conversation</button>;
  }

  return (
    <button onClick={() => startSession({ signedUrl })}>
      Start conversation
    </button>
  );
}

function App({ signedUrl }: { signedUrl: string }) {
  return (
    <ConversationProvider
      onError={(error) => console.error("Conversation error:", error)}
      onPing={(event) => console.log("Estimated latency:", event.ping_ms)}
      onContextUsage={({ model, context_tokens, context_limit_tokens }) =>
        console.log(`${model}: ${context_tokens}/${context_limit_tokens} context tokens`)
      }
    >
      <Agent signedUrl={signedUrl} />
    </ConversationProvider>
  );
}

Configuration

Provider Models
OpenAI gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.5-2026-04-23, gpt-5.4, gpt-5.4-mini, gpt-5.4-nano, gpt-5.4-2026-03-05, gpt-5.4-mini-2026-03-17, gpt-5.4-nano-2026-03-17, gpt-5, gpt-5-mini, gpt-5-nano, gpt-4.1, gpt-4.1-mini, gpt-4.1-nano, gpt-4o, gpt-4o-mini, gpt-4-turbo
Anthropic claude-opus-4-7, claude-sonnet-4-6, claude-sonnet-4-5, claude-sonnet-4, claude-haiku-4-5, claude-3-7-sonnet, claude-3-5-sonnet, claude-3-haiku
Google gemini-3.7-flash, gemini-3.6-flash, gemini-3.1-flash-lite-preview, gemini-3.1-pro-preview, gemini-3-pro-preview, gemini-3-flash-preview, gemini-2.5-flash, gemini-2.5-flash-lite, gemini-2.0-flash, gemini-2.0-flash-lite
ElevenLabs glm-45-air-fp8, qwen3-30b-a3b, qwen36-35b-a3b, qwen35-35b-a3b, qwen35-397b-a17b, gpt-oss-120b
Custom custom-llm (bring your own endpoint)

Use GET /v1/convai/llm/list to inspect the current model catalog, including deprecation state, token/context limits, capability flags such as image-input support, and model-specific reasoning effort support.

Popular voices: JBFqnCBsd6RMkjVDRZzb (George), EXAVITQu4vr4xnSDxMaL (Sarah), onwK4e9ZLuTAKqWW03F9 (Daniel), XB0fDUnXU5powFXDhCwa (Charlotte)

Turn eagerness: patient (waits longer for user to finish), normal, or eager (responds quickly)

See [Agent Configuration](references/agent-configuration.md) for all options.

System Prompt Structure

Section the prompt with markdown headings — the model prioritizes and interprets instructions more reliably (prompting guide):

# Personality   – named character, 2-3 traits
# Environment   – where they work, who they talk to
# Tone          – vocal style as 4-5 bullets
# Goal          – what success looks like (numbered for multi-step flows)

Keep instructions short and action-based. Mark critical steps with "This step is important." For critical refusal/safety rules, include concise instructions in the prompt and also configure independent custom Guardrails via platform_settings.guardrails (see [Guardrails](#guardrails)).

Tools

Extend agents with webhook, client, or built-in system tools. Tools are defined inside conversation_config.agent.prompt:

Workspace environment variables can resolve per-environment server tool URLs, headers, and auth connections, and runtime system variables such as {{system__conversation_history}} can pass full conversation context into tool calls when needed.

"prompt": {
    "prompt": "You are a helpful assistant that can check the weather.",
    "llm": "gemini-2.0-flash",
    "tools": [
        # Webhook: server-side API call
        {"type": "webhook", "name": "get_weather", "description": "Get weather",
         "api_schema": {"url": "https://api.example.com/weather", "method": "POST",
             "request_body_schema": {"type": "object", "properties": {"location": {"type": "string"}}, "required": ["location"]}}},
        # Client: runs in the browser
        {"type": "client", "name": "show_product", "description": "Display a product",
         "parameters": {"type": "object", "properties": {"productId": {"type": "string"}}, "required": ["productId"]}}
    ],
    "built_in_tools": {
        "end_call": {},
        "transfer_to_number": {"transfers": [{"transfer_destination": {"type": "phone", "phone_number": "+1234567890"}, "condition": "User asks for human support"}]},
        "start_procedure": {}
    }
}

Client tools run in browser:

clientTools: {
  show_product: async ({ productId }) => {
    document.getElementById("product").src = `/products/${productId}`;
    return { success: true };
  }
}

See [Client Tools Reference](references/client-tools.md) for complete documentation.

Built-in System Tools

Set under conversationconfig.agent.prompt.builtin_tools. {} enables defaults; provide description to customize; omit to disable.

Tool Enable for
end_call All agents
language_detection Multilingual agents
transfertonumber Phone-based human escalation
transfertoagent Multi-agent workflows
start_procedure Procedure-guided conversations (see [Procedures](#procedures))
end_procedure Completing active procedures
skip_turn Tutoring / coaching (silent listening)
voicemail_detection Outbound calling
playkeypadtouch_tone IVR navigation

runsubagent is a system tool for delegating a task to another configured agent. Add it to conversationconfig.agent.prompt.tools with params.systemtooltype: "runsubagent" and an agents array. Each entry requires agentid and description; branch_id and a JSON-schema parameters object are optional.

knowledgebase is a system tool for letting the model choose how to inspect attached knowledge. Add it to conversationconfig.agent.prompt.tools with type: "system", a name, and params.systemtooltype: "knowledgebase". Use enabledstrategies to expose any combination of cat, keyword, semantic, and ls:

{
  "type": "system",
  "name": "knowledge_base",
  "description": "Search the attached knowledge base.",
  "params": {
    "system_tool_type": "knowledge_base",
    "enabled_strategies": ["semantic", "keyword"]
  }
}

Integration Tools

Pre-built connectors managed by the platform. Create a connection with credentials, then attach via tool_ids:

Integration Use case
calcom Scheduling appointments
salesforce CRM lookups, case creation
hubspot CRM, marketing, contacts
zendesk Support ticketing

Three-step flow: POST /v1/convai/api-integrations/{id}/connectionsGET /v1/convai/api-integrations/{id}/toolsPOST /v1/convai/tools with apiintegrationid and apiintegrationconnectionid. Attach to the agent with "prompt": {"toolids": ["toolxxxx"]}. Inline tools and toolids can coexist — prefer an integration over a duplicate custom webhook.

Public-API Webhook Examples

No-auth APIs useful for prototypes (URLs must be HTTPS):

Tool URL Purpose
get_weather https://wttr.in/{location}?format=j1 Current weather
search_wikipedia https://en.wikipedia.org/api/rest_v1/page/summary/{topic} Topic summary
getexchangerate https://open.er-api.com/v6/latest/{base_currency} FX rates

Workflows

Route conversations through discrete steps with branching logic. Define under the agent's top-level workflow field. Reference: Agent Workflows.

Node types: start (ID must be "startnode"), end, overrideagent (subagent step with label + additionalprompt), dispatchtool (executes a tool with success/failure routing), agenttransfer, transferto_number.

Edge types: unconditional, llm (natural-language condition), expression (deterministic data check). Tool nodes have separate success/failure edges.

Scope tools per step with additionaltoolids on a node — prevents the wrong tool firing at the wrong step. Set additionaltoolids: [] on conversational routing nodes such as greeting and classify_intent so they only converse:

{
  "type": "override_agent",
  "label": "Book Appointment",
  "additional_prompt": "Discuss preferred dates and doctors. Show the booking form once agreed.",
  "entry_behavior": "wait_for_user",
  "additional_tool_ids": ["show_booking_form", "display_appointment_card"],
  "position": {"x": 0, "y": 400}
}

Include position ({x, y}) on every node so the editor renders cleanly. Start at y=0, put end at the bottom, and space branches horizontally at x=-150 and x=150; suggested spacing is 200px vertical between levels and 300px horizontal between branches. Keep workflows to 4-7 nodes and always have a path to end.

Use entrybehavior on overrideagent nodes to choose whether a sub-agent speaks immediately (generateimmediately), waits for user input (waitfor_user), or lets the platform decide (auto).

For nested agent transfers, set enablenesting on a standaloneagent node and returnwhennested on an end node that should return control to the parent workflow.

Procedures

Reusable instruction blocks an agent runs when a trigger matches. A procedure is free_form (markdown guidance the agent adapts, and the only type that can reference knowledge base documents) or deterministic (ordered, typed steps for flows that must run consistently). See [Using the Procedure API](references/using-procedure-api.md) for the full CLI and SDK flow, and [Writing Procedures](references/writing-procedures.md) for the step schema and authoring rules.

Procedures live on an agent branch, and every write stages a per-user draft:

Operation Call
List, create, read, update, discard, remove /v1/convai/agents/{agentid}/branches/{branchid}/procedures... (procedures. and procedures.drafts. in the SDKs)
Compile POST .../procedures/compile (procedures.compile)
Publish PATCH /v1/convai/agents/{agentid}?branchid=... (agents.update)

Semantics worth knowing before writing any of these calls:

  • Nothing reaches the live agent until you publish. Publishing is not a procedure endpoint; one PATCH on the agent versions every changed procedure draft on the branch.
  • GET .../procedures/{procedure_id} reads branch HEAD and returns 404 until that procedure's first publish. Read the /draft variant to see a procedure you just created; do not retry the create.
  • Compile only when structured (deterministic) procedures changed. Compilation turns them into workflow nodes, so the publish must carry the workflow that compile returned. Free-form-only changes publish without compiling, because the agent loads free-form procedures from their published versions.
  • Compile validates structured content and is the only way to check it. On 400 it returns errors keyed by procedure ID with the offending field path; repair the draft and compile again rather than publishing.
  • A draft update replaces the whole body. Read the draft first, then resend name, type, and trigger alongside the new content.
  • content is markdown for a free_form procedure, and a JSON-encoded object with a trigger and a steps array for a deterministic one. Serialize it; do not hand-escape quotes.
  • Routing is driven by the trigger text, not the procedure name. Write concrete, non-overlapping triggers that cover the phrasings a user would actually say.
  • To restrict the starting agent to selected procedures for one conversation, enable platformsettings.overrides.enableprocedureidsfromclient, then pass their IDs as procedureids in conversation initiation data. An empty list disables all procedures for that starting agent.
  • Procedure APIs require elevenlabs (Python) or @elevenlabs/elevenlabs-js at 2.60.0 or newer.

Guardrails

Layered safety enforcement that runs independently of the LLM — configured under platform_settings.guardrails, not in the system prompt. Reference: Guardrails.

"platform_settings": {
  "guardrails": {
    "version": "1",
    "focus": {"is_enabled": true},
    "prompt_injection": {"is_enabled": true},
    "content": {"config": {"harassment": {"is_enabled": true, "threshold": 0.5}}},
    "custom": {
      "config": {
        "configs": [{
          "is_enabled": true,
          "name": "No medical diagnoses",
          "prompt": "Block the agent from providing medical diagnoses or treatment advice.",
          "execution_mode": "blocking",
          "model": "gemini-2.5-flash-lite",
          "history_message_count": 1,
          "trigger_action": {"type": "retry", "feedback": "Reason: {{trigger_reason}}"}
        }]
      }
    }
  }
}

Types: focus (on-topic), promptinjection (manipulation defense), content (category filters), custom (LLM-evaluated domain rules). Content categories include harassment, profanity, sexual, violence, selfharm, and medicalandlegalinformation — threshold range 0.01.0 (default 0.3). Custom rules use executionmode: "blocking" with a model, historymessagecount, and trigger_action (e.g., retry with feedback). Custom guardrails evaluate in parallel and fail-open.

Per vertical: healthcare/finance/legal → enable medicalandlegalinformation; education/youth → sexual/violence/selfharm/profanity; support/sales → harassment/profanity. All agents benefit from focus + prompt_injection + 2-4 custom rules.

Testing Agents

Three test types via POST /v1/convai/agent-testing/create, then attached with PATCH on the agent. Reference: Agent Testing.

Type Purpose
llm Scenario test — does the agent respond appropriately to a message?
tool Tool-call test — right tool, right parameters?
simulation Multi-turn flow with a simulated user persona
// Tool-call test (snake_case throughout; chat_history role is "user" or "agent")
{
  "name": "Books with correct doctor and date",
  "type": "tool",
  "chat_history": [
    {"role": "user", "message": "Dr. Smith on March 5 at 2pm", "time_in_call_secs": 10}
  ],
  "tool_call_parameters": {
    "referenced_tool": {"id": "show_booking_form", "type": "client"},
    "parameters": [
      {"path": "doctor_name", "eval": {"type": "llm", "description": "Should reference Dr. Smith"}},
      {"path": "date", "eval": {"type": "regex", "pattern": "2025-03-05|March 5"}}
    ]
  }
}

Eval strategies: exact, regex, llm. Prompt evaluation criteria can use binary scoring or numeric scoring with scoringmode: "numericuniform", maxscore, and scoreinstructions; numeric scores are normalized into the aggregate conversation success percentage. Attach via an agent update:

elevenlabs agents update --agent-id "your-agent-id" \
  --json '{"platform_settings": {"testing": {"attached_tests": [{"test_id": "test_xxxx"}]}}}'

Run selected tests with POST /v1/convai/agents/{agentid}/run-tests. The request body requires tests and accepts repeatcount from 1 to 50 for repeated runs. Simulation tests can define up to 30 successconditions prompts; all criteria are evaluated and merged into the final result. Simulation tests can also define toolmockoverrides, keyed by tool ID, to replace shared response mocks for one test. Each override is an array of mocks with a required mockresult; set iserror: true to exercise a tool-failure path. Overrides only apply to tools enabled for mocking through toolmockconfig. For completed conversations, rerun one evaluation criterion with POST /v1/convai/conversations/{conversationid}/analysis/evaluations/run and a request body containing evaluation_id.

Widget Embedding

<elevenlabs-convai agent-id="your-agent-id"></elevenlabs-convai>
<script src="https://unpkg.com/@elevenlabs/convai-widget-embed" async type="text/javascript"></script>

Customize with attributes: avatar-image-url, action-text, start-call-text, end-call-text.

See [Widget Embedding Reference](references/widget-embedding.md) for all options.

Outbound Calls

Make outbound phone calls using your agent via Twilio or Exotel integration:

The examples below use Twilio. See the reference for Exotel usage.

Python

response = client.conversational_ai.twilio.outbound_call(
    agent_id="your-agent-id",
    agent_phone_number_id="your-phone-number-id",
    to_number="+1234567890",
    call_recording_enabled=True
)
print(f"Call initiated: {response.conversation_id}")

JavaScript

const response = await client.conversationalAi.twilio.outboundCall({
  agentId: "your-agent-id",
  agentPhoneNumberId: "your-phone-number-id",
  toNumber: "+1234567890",
  callRecordingEnabled: true,
});

CLI

elevenlabs agents twilio outbound_call \
  --agent-id "your-agent-id" \
  --agent-phone-number-id "your-phone-number-id" \
  --to-number "+1234567890" \
  --call-recording-enabled true

See [Outbound Calls Reference](references/outbound-calls.md) for provider-specific endpoints, configuration overrides, and dynamic variables.

Managing Agents

Using CLI (Recommended)

# List agents and check status
elevenlabs agents list
elevenlabs agents status

# Import agents from platform to local config
elevenlabs agents pull                      # Import all agents
elevenlabs agents pull --agent <agent-id>   # Import specific agent

# Push local changes to platform
elevenlabs agents push              # Upload configurations
elevenlabs agents push --dry-run    # Preview changes first

# Add tools
elevenlabs tools add-webhook "Weather API"
elevenlabs tools add-client "UI Tool"

Project Structure

The CLI creates a project structure for managing agents:

your_project/
├── agents.json       # Agent definitions
├── tools.json        # Tool configurations
├── tests.json        # Test configurations
├── agent_configs/    # Individual agent configs
├── tool_configs/     # Individual tool configs
└── test_configs/     # Individual test configs

SDK Examples

# List
agents = client.conversational_ai.agents.list()

# Get
agent = client.conversational_ai.agents.get(agent_id="your-agent-id")

# Update (partial - only include fields to change)
client.conversational_ai.agents.update(agent_id="your-agent-id", name="New Name")
client.conversational_ai.agents.update(agent_id="your-agent-id",
    conversation_config={
        "agent": {"prompt": {"prompt": "New instructions", "llm": "claude-sonnet-4"}}
    })

# Delete
client.conversational_ai.agents.delete(agent_id="your-agent-id")

See [Agent Configuration](references/agent-configuration.md) for all configuration options and SDK examples.

Error Handling

try:
    agent = client.conversational_ai.agents.create(...)
except Exception as e:
    print(f"API error: {e}")

Common errors: 401 (invalid key), 404 (not found), 422 (invalid config), 429 (rate limit)

References

  • [Installation Guide](references/installation.md) - SDK setup and migration
  • [Agent Configuration](references/agent-configuration.md) - All config options and CRUD examples
  • [Client Tools](references/client-tools.md) - Webhook, client, and system tools
  • [Using the Procedure API](references/using-procedure-api.md) - Procedure CLI and SDK flow, compile and publish
  • [Writing Procedures](references/writing-procedures.md) - Trigger and content authoring, step schema
  • [Widget Embedding](references/widget-embedding.md) - Website integration
  • [Outbound Calls](references/outbound-calls.md) - Phone call integrations