Skip to main content
MindStudio
Pricing
Blog About
My Workspace

ElevenLabs Voice Widget Security: 5 Settings to Lock Down Before You Go Public

Your ElevenLabs widget embed is a single HTML snippet — anyone can steal it. Five security settings to configure before you deploy publicly.

MindStudio Team RSS
ElevenLabs Voice Widget Security: 5 Settings to Lock Down Before You Go Public

Your ElevenLabs Widget Is a Single HTML Snippet — Here Are 5 Settings to Lock It Down

Anyone who views your page source can steal your ElevenLabs voice widget in about 10 seconds. The embed is literally one <script> tag with your agent ID baked in. Copy it, paste it on another site, and that site now has a fully functional voice agent running on your ElevenLabs credits. This is not a theoretical attack — it’s the default behavior of every public widget deployment, and most people building voice agents with ElevenLabs don’t realize it until they get a surprise bill.

There are 5 specific settings you should configure before you make any ElevenLabs widget public. Some are in the ElevenLabs security tab, some are in the widget configuration, and one is a Cal.com setting that will confuse you if you don’t know it exists. All of them matter.


The Threat Model Is Simpler Than You Think

The ElevenLabs widget embed is a single HTML snippet. You copy it from the widget tab in your ElevenLabs dashboard and drop it into your site. That’s it — no authentication, no token exchange, no per-user session. The snippet contains your agent ID, and the agent ID is enough for anyone to spin up a conversation against your account.

If you’ve built a voice agent with a professional voice clone — trained on, say, 4 hours of your own voice — and you’ve wired it up to tools like a Cal.com booking integration, you’ve put real work into that agent. Leaving the widget unprotected means anyone who inspects your page source can clone that experience onto their own domain and run it indefinitely at your expense.

The attack surface is small, which is actually good news. You don’t need a complex security architecture. You need five specific settings configured correctly.


Setting 1: Lock the Widget to Your Hostname in ElevenLabs Security

The most important setting is in the ElevenLabs agent dashboard under the Security tab. You can restrict which hostnames are allowed to load your widget. Add your domain to the allow list — yourdomain.com, not a wildcard — and the widget will refuse to initialize on any other origin.

This is the primary defense. Even if someone copies your HTML snippet verbatim and pastes it into their own site, the ElevenLabs backend will reject the request because the Origin header won’t match your allow list.

The setting is labeled something like “allowed hostnames” or “host restrictions” depending on which version of the dashboard you’re looking at. It’s not enabled by default. You have to go find it and turn it on.

One thing to be aware of: localhost is a separate origin from your production domain. During development you’ll want to temporarily add localhost:3000 (or whatever port you’re running on) to the allow list, then remove it before you ship. Leaving localhost in production allow lists is a common mistake.


Setting 2: Configure the Widget Allow-Domains List

Separately from the agent-level security settings, the ElevenLabs widget itself has an allow-domains configuration. This is in the widget tab of your dashboard, not the security tab. It’s a second layer of domain restriction that operates at the widget embed level rather than the agent API level.

Both settings exist, and both should be configured. They’re not redundant — they operate at different points in the request lifecycle. The agent-level hostname lock happens server-side when the widget tries to authenticate. The widget allow-domains list is a client-side guard that can prevent the widget from even attempting to initialize on an unauthorized domain.

Think of it as defense in depth. If one layer has a misconfiguration, the other catches it.


Setting 3: Set a Per-Call Duration Cap

An uncapped voice agent call is an open billing meter. If someone — malicious or just curious — starts a conversation and walks away, the call keeps running. ElevenLabs charges by the minute of audio generated, so a single abandoned session can run up meaningful costs.

The fix is a maximum call duration setting. Set a ceiling — something like 10 or 15 minutes for a sales or support agent — and the session terminates automatically when it hits that limit. For most legitimate use cases, 10 minutes is more than enough. If your agent is doing something that genuinely requires longer sessions, you can raise it, but start conservative.

This is also good UX. A voice agent that can run indefinitely tends to drift. Capping the session forces you to think about what a successful conversation looks like and design the agent to get there efficiently.

Cursor
ChatGPT
Figma
Linear
GitHub
Vercel
Supabase
remy.msagent.ai

Seven tools to build an app. Or just Remy.

Editor, preview, AI agents, deploy — all in one tab. Nothing to install.

The duration cap is separate from the rate limiting setting, which we’ll cover next. You want both.


Setting 4: Rate-Limit the Widget on Public Pages

If your widget is on a public-facing page — a landing page, a marketing site, anywhere without authentication — you need rate limiting. Without it, a single IP address can open hundreds of concurrent sessions or thousands of sequential ones.

ElevenLabs has per-widget rate limiting settings. Configure a reasonable limit: something like 5 sessions per IP per hour is a reasonable starting point for a B2B sales agent. You can tune this based on your actual traffic patterns, but the default (no limit) is wrong for any public deployment.

Rate limiting won’t stop a determined attacker with a botnet, but it will stop the most common abuse patterns: automated scripts, curious developers poking at your widget, and the occasional person who thinks it’s funny to run your agent in a loop.

If you’re building more complex agent infrastructure — orchestrating multiple models, chaining tools, managing sessions across different surfaces — platforms like MindStudio handle a lot of this orchestration layer for you, with 200+ models and 1,000+ integrations available without writing the session management code yourself. But for a single ElevenLabs widget, the built-in rate limiting is sufficient if you actually turn it on.


Setting 5: The Cal.com Minimum Notice Setting (This One Will Confuse You)

This one isn’t a security setting in the traditional sense, but it will make your agent look broken in a way that’s hard to debug if you don’t know about it.

If you’ve integrated Cal.com for appointment booking — using the check_availability and book_appointment tools that Claude Code will wire up for you — you’ll notice that the first available slot the agent returns is often later than you expect. If it’s 4:30 PM and your calendar shows availability until 9:00 PM, the agent might only offer 6:30 PM as the earliest slot.

The reason is Cal.com’s minimum notice setting, which defaults to 2 hours. The platform won’t allow bookings within 2 hours of the current time. So at 4:30 PM, the earliest bookable slot is 6:30 PM. This is a Cal.com configuration, not a bug in your agent or your tool implementation.

You can find this under the event type settings in Cal.com, under Limits. Change it to whatever makes sense for your workflow — 30 minutes if you want near-real-time bookings, or leave it at 2 hours if you need buffer time to prepare.

The reason this matters for security and reliability: if you don’t understand why the agent is returning unexpected availability, you might start debugging the wrong thing. In the build that inspired this post, Claude Code actually identified a separate availability bug — the check_availability tool was querying Cal.com in UTC instead of Central time — by reading the raw conversation transcript at turn 16. The UTC offset and the minimum notice setting were two different issues producing similar symptoms (fewer available slots than expected). Knowing about the minimum notice setting lets you rule it out quickly and focus on the real bugs.

The .env file pattern matters here too. Your Cal.com API key and ElevenLabs API key should both be in environment variables — CAL_API_KEY and ELEVENLABS_API_KEY — never committed to your repository. If you’re deploying to Vercel, set these in the Vercel environment variables dashboard, not in your codebase. This is basic credential hygiene, but it’s worth stating explicitly because the Cal.com API key gives write access to your calendar — it can create bookings, not just read availability.


The Deployment Checklist Before You Go Public

To make this concrete, here’s the sequence of checks before you push a widget to production:

In ElevenLabs Security settings:

  • Hostname allow list configured to your production domain only
  • localhost removed from the allow list

In ElevenLabs Widget settings:

  • Allow-domains list configured
  • Per-call duration cap set (10–15 minutes is a reasonable default)
  • Rate limiting enabled

In Cal.com:

  • Minimum notice setting reviewed and set intentionally
  • API key stored in .env, not in source code
  • .env in .gitignore

In your deployment (Vercel or equivalent):

  • CAL_API_KEY and ELEVENLABS_API_KEY set as environment variables in the platform dashboard
  • GitHub repo does not contain any API keys

If you’re deploying a Next.js site to Vercel, the import flow is: connect your GitHub repo, set the Next.js preset, add your environment variables. The widget embed — that single HTML snippet from the ElevenLabs widget tab — goes into your site’s HTML, and Vercel handles the rest.

For teams building more complex applications around voice agents, the spec-driven approach is worth considering. Remy compiles annotated markdown specs into complete TypeScript applications — backend, database, auth, deployment — which means your security requirements can live in the spec alongside your feature requirements, rather than being retrofitted after the fact.


What the Widget Architecture Actually Exposes

Understanding why these settings matter requires understanding what the widget actually is. The voice agent loop is: microphone → transcription → LLM → optional tool call → TTS → speaker. The widget is just the client-side entry point to that loop. Every turn in the conversation costs money: transcription, LLM inference, TTS generation.

The agent itself has four configurable components: persona (the system prompt), voice, knowledge base, and tools. All of these are configured server-side in ElevenLabs. The widget snippet is just a pointer to that configuration. Which means whoever has the snippet can access all of it — your persona, your voice clone, your knowledge base, your tool integrations — at your expense.

The three deployment modes for ElevenLabs agents are dashboard testing, website widget embed, and Twilio phone number. The dashboard test mode is inherently private. The Twilio phone number is gated by the phone number itself. The website widget embed is the only mode that’s trivially public by default, which is why it needs the most attention.

One coffee. One working app.

You bring the idea. Remy manages the project.

WHILE YOU WERE AWAY
Designed the data model
Picked an auth scheme — sessions + RBAC
Wired up Stripe checkout
Deployed to production
Live at yourapp.msagent.ai

If you’re building agents that need to operate across multiple surfaces — voice widget, phone, and maybe a chat interface — you’ll want to think about how your security model scales. Claude Code agentic workflow patterns covers some of the orchestration patterns that become relevant when you’re managing agents across multiple deployment targets.


The Honest Assessment

The ElevenLabs widget is genuinely easy to deploy. The security settings are also genuinely easy to configure — they’re not buried or complicated. The problem is that nothing in the default setup prompts you to configure them. You copy the snippet, paste it, it works, you ship it.

The five settings above — hostname lock, widget allow-domains, duration cap, rate limiting, and Cal.com minimum notice — take maybe 20 minutes to configure correctly. The cost of not configuring them is unbounded, because you’ve handed anyone with browser dev tools an open tab to your ElevenLabs account.

Voice agents built this way — with real tool integrations, professional voice clones, and knowledge bases trained on actual content — represent real investment. The security settings exist to protect that investment. Use them before you go public, not after you get the bill.

For teams thinking about how to build and iterate on agents without getting buried in API documentation, building AI agents for specific workflows and keeping agents running reliably are worth reading alongside the security considerations here. The build is the fun part. The security configuration is what makes it viable to leave running.

Presented by MindStudio

No spam. Unsubscribe anytime.