Subchapter 1.6
references/widget-embedding.mdMarkdown8 KBView on GitHub
This creates a floating launcher. Voice-only agents show a call entry point, text-only agents show a message entry point, and multimodal agents show both.
Note: Widgets currently require public agents with authentication disabled. For authenticated flows, use the SDKs.
| Attribute | Description |
|---|---|
agent-id | Your ElevenLabs agent ID |
signed-url | Alternative to agent-id when using signed URLs |
| Attribute | Description | Default |
|---|---|---|
avatar-image-url | URL for agent avatar image | ElevenLabs logo |
avatar-orb-color-1 | Primary orb gradient color | #2792dc |
avatar-orb-color-2 | Secondary orb gradient color | #9ce6e6 |
| Attribute | Description | Default |
|---|---|---|
action-text | Tooltip when hovering | “Talk to AI” |
start-call-text | Button to start call | “Start call” |
end-call-text | Button to end call | “End call” |
expand-text | Expand chat button | “Open” |
collapse-text | Collapse chat button | “Close” |
listening-text | Listening state label | “Listening…” |
speaking-text | Speaking state label | “Assistant speaking” |
| Attribute | Description | Default |
|---|---|---|
variant | Widget style: compact or expanded | compact |
server-location | Server region (us, eu-residency, in-residency, global) | us |
dismissible | Allow the user to minimize the widget | false |
disable-banner | Hide “Powered by ElevenLabs” | false |
show-resize-button | Show the expand and collapse control in the widget header | true |
<elevenlabs-convai
agent-id="your-agent-id"
avatar-image-url="https://example.com/your-avatar.png"
></elevenlabs-convai><elevenlabs-convai
agent-id="your-agent-id"
avatar-orb-color-1="#ff6b6b"
avatar-orb-color-2="#ffd93d"
></elevenlabs-convai><elevenlabs-convai
agent-id="your-agent-id"
action-text="Chat with our AI assistant"
start-call-text="Begin conversation"
end-call-text="Hang up"
></elevenlabs-convai><elevenlabs-convai
agent-id="your-agent-id"
variant="expanded"
></elevenlabs-convai>Embedded chat widgets can accept image and PDF uploads when the agent uses a multimodal LLM and
conversation_config.conversation.file_input.enabled is enabled. Configure
max_files_per_conversation to cap uploads per conversation.
<elevenlabs-convai
agent-id="your-agent-id"
avatar-image-url="https://example.com/support-agent.png"
avatar-orb-color-1="#4f46e5"
avatar-orb-color-2="#818cf8"
action-text="Talk to Support"
start-call-text="Start voice chat"
end-call-text="End conversation"
expand-text="Open assistant"
collapse-text="Minimize"
></elevenlabs-convai>The widget uses Shadow DOM but exposes CSS custom properties:
elevenlabs-convai {
--elevenlabs-convai-widget-width: 400px;
--elevenlabs-convai-widget-height: 600px;
}By default, the widget appears in the bottom-right corner. Override with CSS:
elevenlabs-convai {
position: fixed;
bottom: 20px;
right: 20px;
/* Or position differently */
left: 20px;
right: auto;
}elevenlabs-convai {
z-index: 9999;
}Access the widget element to control it programmatically:
<elevenlabs-convai id="my-widget" agent-id="your-agent-id"></elevenlabs-convai>
<script>
const widget = document.getElementById("my-widget");
// Start a conversation
widget.startConversation();
// End the conversation
widget.endConversation();
// Listen for events
widget.addEventListener("conversationStarted", () => {
console.log("Conversation started");
});
widget.addEventListener("conversationEnded", () => {
console.log("Conversation ended");
});
</script>Hide the default widget and use your own button:
<style>
elevenlabs-convai {
display: none;
}
</style>
<button onclick="document.getElementById('widget').startConversation()">
Talk to AI
</button>
<elevenlabs-convai id="widget" agent-id="your-agent-id"></elevenlabs-convai>For agents with authentication enabled, pass a signed URL:
<elevenlabs-convai id="widget" agent-id="your-agent-id"></elevenlabs-convai>
<script>
async function startAuthenticatedConversation() {
// Get signed URL from your backend
const response = await fetch("/api/get-signed-url");
const { signedUrl } = await response.json();
const widget = document.getElementById("widget");
widget.setAttribute("signed-url", signedUrl);
widget.startConversation();
}
</script>Your backend:
@app.get("/api/get-signed-url")
def get_signed_url():
signed_url = client.conversational_ai.conversations.get_signed_url(
agent_id="your-agent-id"
)
return {"signedUrl": signed_url.signed_url}/* Desktop: bottom-right */
elevenlabs-convai {
position: fixed;
bottom: 20px;
right: 20px;
}
/* Mobile: full-width bottom */
@media (max-width: 768px) {
elevenlabs-convai {
bottom: 0;
right: 0;
left: 0;
--elevenlabs-convai-widget-width: 100%;
}
}The widget is touch-optimized by default. For better mobile UX:
@media (max-width: 768px) {
elevenlabs-convai {
/* Larger touch target */
transform: scale(1.1);
transform-origin: bottom right;
}
}You can have multiple widgets for different agents:
<elevenlabs-convai
agent-id="support-agent-id"
action-text="Support"
style="right: 20px"
></elevenlabs-convai>
<elevenlabs-convai
agent-id="sales-agent-id"
action-text="Sales"
style="right: 100px"
></elevenlabs-convai>function App() {
useEffect(() => {
// Load widget script
const script = document.createElement("script");
script.src = "https://unpkg.com/@elevenlabs/convai-widget-embed";
script.async = true;
document.body.appendChild(script);
return () => document.body.removeChild(script);
}, []);
return (
<div>
<elevenlabs-convai agent-id="your-agent-id"></elevenlabs-convai>
</div>
);
}<template>
<div>
<elevenlabs-convai agent-id="your-agent-id"></elevenlabs-convai>
</div>
</template>
<script setup>
import { onMounted } from "vue";
onMounted(() => {
const script = document.createElement("script");
script.src = "https://unpkg.com/@elevenlabs/convai-widget-embed";
script.async = true;
document.body.appendChild(script);
});
</script>import Script from "next/script";
export default function Page() {
return (
<>
<Script
src="https://unpkg.com/@elevenlabs/convai-widget-embed"
strategy="lazyOnload"
/>
<elevenlabs-convai agent-id="your-agent-id"></elevenlabs-convai>
</>
);
}If using authentication, ensure your domain is in the agent’s allowlist:
platform_settings={
"auth": {
"enable_auth": True,
"allowlist": ["https://yourdomain.com"]
}
}