The ElevenLabs Voice Agent adds a phone button to the Chatwoot live-chat widget so visitors can start a real-time AI voice call without leaving the page. Every spoken turn — both what the visitor says and what the agent replies — is automatically posted into the same Chatwoot conversation, so your support team sees the full voice exchange alongside any text messages the visitor sends.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/jAtInn71/chatwoot-costom/llms.txt
Use this file to discover all available pages before exploring further.
How it works end-to-end
The feature is a six-step chain. Each piece must be in place for the button to appear and calls to be recorded. 1. Dashboard saves voice agent config per inbox An admin opens Settings → Inboxes → <your inbox> → Configuration and fills in the Voice Agent section. Saving writes four values to thechannel_web_widgets table:
selected_feature_flags— toggles bit 5 (elevenlabs_voice) to enable or disable the featurevoice_agent_provider— the AI provider string (currentlyelevenlabs)elevenlabs_agent_id— the ElevenLabs agent ID (also mirrored intovoice_agent_config_data.agent_id)voice_agent_api_key— optional; needed only for private agents
selected_feature_flags, voice_agent_provider, voice_agent_api_key, voice_agent_config_data, and elevenlabs_agent_id. No page reload is required after saving dashboard changes — the next bubble open picks them up automatically.
3. Widget resolves whether to show the button
The voiceAgentConfig Vuex store parses the response and sets three computed values. The voice button is shown only when all three conditions are true:
isVoiceAgentEnabled—selected_feature_flagsincludeselevenlabs_voiceprovider === 'elevenlabs'— the provider field matchesagentIdis non-empty — resolved fromvoice_agent_config_data.agent_idfirst, then theelevenlabs_agent_idcolumn, thenwindow.chatwootConfig
ElevenLabsVoiceButton.vue mounts a hidden <elevenlabs-convai> web component loaded from https://unpkg.com/@elevenlabs/convai-widget-embed. The embed is kept off-screen; visitors only see the custom phone button. Clicking it triggers a start-call action on the embed’s shadow DOM, which opens a WebRTC peer connection to ElevenLabs.
The widget uses the
<elevenlabs-convai> CDN web component instead of the @elevenlabs/client npm package. The npm package bundles LiveKit JS SDK 2.x, which negotiates protocol=17. ElevenLabs’ production LiveKit server is still on protocol 16, causing a NegotiationError: negotiation timed out on the WebRTC side even though the WebSocket signal channel opens. The CDN bundle ships an older LiveKit build that speaks protocol 16 — calls actually connect. If you ever update the bundle by running ./build.sh, this is automatically pulled fresh.<elevenlabs-convai> element fires a custom event (convai-message, message, or transcript) after each completed turn. ElevenLabsVoiceButton.vue listens for these events and POSTs to:
{ source: "user" | "ai", content: "<spoken text>" }. The Rails controller appends the turn to the visitor’s conversation as a regular message.
6. Transcripts appear in the conversation in real time
After each successful POST the widget dispatches conversation/syncLatestMessages, so the visitor sees their voice turns appear in the chat window immediately. Agents on the dashboard see the same messages as normal bubbles, distinguishable by content_attributes.voice_transcript: true.
Agent visibility requirements
Next steps
Configure the voice agent
Step-by-step instructions for enabling the voice agent on an inbox and setting your ElevenLabs agent ID.
Voice call transcripts
How spoken turns are captured, posted to Chatwoot, and displayed in the conversation view.
Troubleshooting
Fix common issues: button not appearing, calls dropping, missing transcripts, and more.