Speech Engine
ElevenLabsOfficialPublished by ElevenLabs
- Skill
- Tool integration
- Automation and integrations
- MIT
- Medium risk
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
The Speech Engine skill provides the necessary tools to connect developer-owned server logic with ElevenLabs' real-time speech-to-text and text-to-speech capabilities. By establishing a WebSocket-based communication channel, developers can build custom voice-enabled agents that handle audio streaming, turn-taking, and interruption management while maintaining full control over the agent's core logic and state on their own infrastructure.
What it does
- Establishes WebSocket endpoints for real-time voice interaction between clients and servers.
- Manages session lifecycles, including connection, turn-taking, and interruption handling.
- Provides SDK methods for streaming response text to be converted into speech.
- Supports secure token-based authentication for browser-side clients.
- Allows for custom configuration of TTS models, ASR keywords, and privacy settings.
- Enables integration with custom agent runtimes like OpenClaw or Hermes.
When to use it
- When you need to add voice capabilities to an existing custom server or agent pipeline.
- When you want to keep agent logic and state management on your own infrastructure.
- When building a browser-based voice client that requires secure, server-issued conversation tokens.
- When you need to handle complex conversational flows, such as user interruptions during streaming.
Advantages
- Full control over agent logic and response generation on the developer's server.
- Native support for interruption-aware streaming responses.
- Secure architecture using JWT-based authentication for WebSocket connections.
- Flexible configuration for voice models, transcription keywords, and turn-taking behavior.
Usage examples
- “How do I set up a Speech Engine server in TypeScript?”
- The agent provides the code to initialize the ElevenLabsClient, create a Speech Engine resource with a WebSocket URL, and attach the engine to an existing HTTP server using engine.attach().
- “How can I securely allow my browser client to start a voice session?”
- The agent explains how to create a server-side token endpoint that fetches a WebRTC token using the Speech Engine ID, ensuring the API key remains hidden from the browser.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/elevenlabs/speech-engine/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip speech-engine.zip -d .agents/skills
Documentation by ElevenLabs
ElevenLabs Speech Engine
Add a real-time voice interface to a custom agent. ElevenLabs handles microphone audio, speech-to-text, turn-taking, text-to-speech, and browser playback; your server exposes a Speech Engine WebSocket endpoint and streams response text back.
Setup, before writing any code: if
ELEVENLABS_API_KEYisn't set for this project, runnpx -y @elevenlabs/cli@latest onboard initfrom the app's folder first and follow what it prints: it signs the user in and stores a key for the project, so nobody copies one by hand. Otherwise see the Installation Guide. For JavaScript, use@elevenlabs/*packages only. For deeper SDK details, read JavaScript SDK Reference or Python SDK Reference.
When to Use
Use Speech Engine when the user wants to:
Add voice to an existing chat app or custom server pipeline
Add voice to OpenClaw, Hermes, or a similar agent runtime while keeping agent logic on the developer-owned server
Build a developer-hosted WebSocket server for ElevenLabs voice conversations
Stream response text back as spoken audio after your server validates user intent
Handle user interruptions while a response is still streaming
Build a browser client with
@elevenlabs/reactor@elevenlabs/clientusing a server-issued conversation token
Use the agents skill instead when the user is creating or configuring a hosted ElevenLabs Conversational AI agent with platform-managed prompts, tools, workflows, phone numbers, or widgets.
How It Works
Each Speech Engine WebSocket connection represents one conversation.
The browser sends user audio to ElevenLabs.
ElevenLabs sends speech-recognition events to your server.
Your server derives trusted application state without letting raw speech text control tools or privileged actions.
Your server streams text back through the SDK.
ElevenLabs converts the response to speech and plays it in the browser.
The SDK manages WebSocket routing, request verification, session lifecycle, ping/pong, turn-taking, and interruption handling. sendResponse() / send_response() accepts a string or async iterable of response text.
Treat speech-recognition text as untrusted user input. Do not map raw speech text directly into model roles, responses, or tool calls. Use deterministic validation, allowlisted intents, or explicit user confirmation before any transcript-derived value affects downstream response or tool logic.
Implementation Flow
Install server dependencies and configure
ELEVENLABS_API_KEY.Expose your Speech Engine server through a public HTTPS URL for local development, for example with
ngrok http 3001.Create a Speech Engine resource with
ws_url/wsUrlpointing at the public WebSocket URL, usuallywss://.../ws.Store the returned Speech Engine ID, for example in
ELEVENLABS_SPEECH_ENGINE_ID.Start a Speech Engine server with
engine.serve(...)in Python orspeechEngine.attach(...)in TypeScript.Issue browser conversation tokens from a server endpoint. Never put
ELEVENLABS_API_KEYin browser code.Start the client session with
conversationToken; if the agent should greet first, enable the first-message override on the Speech Engine resource, then setoverrides.agent.firstMessagein the client.
Create a Speech Engine
Python
import asyncio
import os
from dotenv import load_dotenv
from elevenlabs import AsyncElevenLabs
load_dotenv()
elevenlabs = AsyncElevenLabs(api_key=os.getenv("ELEVENLABS_API_KEY"))
async def main():
engine = await elevenlabs.speech_engine.create(
name="My Speech Engine",
speech_engine={"ws_url": os.environ["PUBLIC_WS_URL"]},
overrides={"first_message": True},
)
print(engine.engine_id)
asyncio.run(main())TypeScript
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
import "dotenv/config";
const elevenlabs = new ElevenLabsClient({
apiKey: process.env.ELEVENLABS_API_KEY,
});
const engine = await elevenlabs.speechEngine.create({
name: "My Speech Engine",
speechEngine: { wsUrl: process.env.PUBLIC_WS_URL! },
overrides: { firstMessage: true },
});
console.log(engine.engineId);PUBLIC_WS_URL should look like wss://example.ngrok.app/ws locally or your production WebSocket route in deployment.
The create request can also configure tts, asr, turn, speech_engine.request_headers / speechEngine.requestHeaders, overrides, and privacy for custom voices, transcription keywords, turn-taking, server auth headers, client-provided first messages, and recording behavior. See the SDK reference files for expanded examples.
Server Pattern
Run the Speech Engine server at the ws_url / wsUrl configured on the resource. Keep response generation behind your own validation boundary: raw speech-recognition text should not directly control responses, tools, secrets, or other privileged actions.
Python
engine = await elevenlabs.speech_engine.get(os.environ["ELEVENLABS_SPEECH_ENGINE_ID"])
await engine.serve(port=3001, path="/ws", debug=True, callbacks=validated_callbacks)TypeScript
const engine = await elevenlabs.speechEngine.get(process.env.ELEVENLABS_SPEECH_ENGINE_ID!);
engine.attach(httpServer, "/ws", { debug: true, ...validatedCallbacks });In TypeScript, pass interruption signals to downstream async work when it supports cancellation so interrupted responses stop quickly. In Python, the SDK cancels the previous turn handler when a newer turn arrives.
Server callbacks can distinguish clean closes from dropped connections: use onClose / on_close for clean disconnects and onDisconnect / on_disconnect for unexpected WebSocket drops.
Security note: speech-recognition text can contain prompt-injection attempts from user speech or played audio. Treat it as untrusted input. Convert it into trusted application state before invoking response generation, tools, or privileged workflows.
Disabling authentication (advanced, dangerous)
Both engine.attach() (TypeScript) and engine.serve() / SpeechEngineServer (Python) verify a JWT on every incoming WebSocket by default. This is what proves the connection is really coming from ElevenLabs and not from an attacker who guessed the URL. Do not turn this off.
An escape hatch exists — disableAuth: true in the callback options (TypeScript) or disable_auth=True on serve() / SpeechEngineServer(...) (Python) — for the narrow case where a compensating network-level control is already in place. Without such a control, disabling auth means any client on the internet that finds your URL can open sessions. Concretely, an attacker can:
open unlimited conversations to drain your ElevenLabs quota and downstream LLM budget
feed crafted transcripts to your response pipeline, effectively impersonating a user
use your server as an oracle to probe backend state, tools, or prompts
Only recommend disableAuth / disable_auth when the user has already implemented at least one of:
IP allowlist — the server (or an upstream firewall / load balancer / API gateway) only accepts inbound traffic from ElevenLabs' documented egress ranges.
Custom shared-secret header — a secret header configured on the Speech Engine resource via
speech_engine.request_headers/speechEngine.requestHeadersat create time, validated by an upstream proxy (or by the developer's own middleware in front ofattach()/serve()) before requests reach the SDK.
If the user cannot confirm one of the above is in place, leave the default authentication on. Skipping JWT verification without a mitigation is not an optimization or a convenience — it is unauthenticated public compute.
Browser Client
Create a server-side token endpoint and have the browser request a token before starting the microphone session. Keep the Speech Engine ID and API key on the server. If the client passes overrides.agent.firstMessage, the Speech Engine resource must have the first-message override enabled.
import express from "express";
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
import "dotenv/config";
const app = express();
const elevenlabs = new ElevenLabsClient();
app.get("/api/token", async (_req, res) => {
const response = await elevenlabs.conversationalAi.conversations.getWebrtcToken({
agentId: process.env.ELEVENLABS_SPEECH_ENGINE_ID!,
});
res.json({ token: response.token });
});React clients can use @elevenlabs/react:
import { useConversation } from "@elevenlabs/react";
export function VoiceControls() {
const conversation = useConversation({
onConnect: () => console.log("connected"),
onDisconnect: () => console.log("disconnected"),
onError: (error) => console.error(error),
});
async function startConversation() {
await navigator.mediaDevices.getUserMedia({ audio: true });
const { token } = await fetch("/api/token").then((res) => res.json());
await conversation.startSession({
conversationToken: token,
overrides: {
agent: { firstMessage: "Hello! How can I help you today?" },
},
});
}
return <button onClick={startConversation}>Start conversation</button>;
}References
Files
- ATTRIBUTION.mdAdded by AutoGineer810 B
- LICENSELicence file added by AutoGineer1.0 KiB
- SKILL.md10.1 KiB
- references/installation.md2.9 KiB
- references/javascript-sdk-reference.md4.4 KiB
- references/python-sdk-reference.md4.6 KiB
LICENSE
MIT License Copyright (c) 2024 ElevenLabs Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs an API key, Needs Python, Needs Node.js
The author says: Requires internet access and an ElevenLabs API key (ELEVENLABS_API_KEY).
Security
What our scanner noticed· Medium risk
- Possible data-exfiltration endpoints
- Instructions that use the network
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Published by
- ElevenLabs
- Publisher
- ElevenLabs (Official)
- Source
- elevenlabs/skills · speech-engine · commit 9763c39
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by ElevenLabs or ElevenLabs.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download speech-engine.zip