ElevenLabs Agent Simulator is a Chrome extension that brings SDK-level conversation testing capabilities directly into the ElevenLabs web interface. It enables developers to simulate realistic dialogues between their conversational AI agent and an automated user agent, allowing them to test prompts, refine settings, and identify edge cases before production deployment.
Note: No background service worker or content scripts needed - the popup handles everything directly.
Note: The ElevenLabs Node.js SDK (@elevenlabs/elevenlabs-js) cannot be used in browser environments. The browser SDK (@elevenlabs/client) is designed for real-time voice conversations via WebSocket/WebRTC, not for the simulateConversation API. We’ll make direct HTTPS REST API calls to https://api.elevenlabs.io/v1/convai/agents/{agent_id}/simulate-conversation using the Fetch API.
activeTabelevenlabs.io/*, api.elevenlabs.io/*src/utils/url-parser.ts)elevenlabs.io/app/conversational-ai/[agent-id]/*src/popup/popup.html)src/popup/popup.css)src/popup/popup.ts)Key Architecture: The ElevenLabs REST API’s simulate-conversation endpoint is extremely simple:
src/popup/popup.ts)runSimulation(apiKey: string, agentId: string, userPrompt: string)const response = await fetch(
`https://api.elevenlabs.io/v1/convai/agents/${agentId}/simulate-conversation`,
{
method: 'POST',
headers: {
'xi-api-key': apiKey,
'Content-Type': 'application/json',
},
body: JSON.stringify({
simulation_specification: {
simulated_user_config: {
prompt: {
prompt: userPrompt,
llm: 'gpt-4o', // hardcoded for now
temperature: 0.7, // hardcoded for now
},
},
},
}),
}
);
if (!response.ok) {
throw new Error(`API Error: ${response.status} ${response.statusText}`);
}
return await response.json();
JSON.stringify(response, null, 2)Problem: Some agents require dynamic variables (e.g., user_name, order_id) to be provided in the simulation. Without these, the API returns a 400 error:
{
"detail": {
"status": "missing_dynamic_variables",
"message": "Missing required dynamic variables in first message: {'user_name'}"
}
}
src/popup/popup.html)src/popup/popup.css)src/popup/popup.ts)dynamic_variables object: { [key: string]: string }runSimulation() function signature to accept dynamicVariables: Record<string, string>dynamic_variables in API request body:
body: JSON.stringify({
simulation_specification: {
simulated_user_config: {
prompt: {
prompt: userPrompt,
llm: 'gpt-4o',
temperature: 0.7,
},
},
dynamic_variables: dynamicVariables, // Add this field
},
})
fetchAgentConfig() function that calls GET /v1/convai/agents/{agent_id} endpointconversation_config.agent.dynamic_variables.dynamic_variable_placeholders in responsehandleLoadVariables() function with:
addVariableRow() to accept optional default key/value parametersUser Flow:
Benefits:
Problem: Currently, when the popup closes (user clicks outside or switches tabs), all input values are lost. When reopening the popup, users must re-enter their API key, simulated user prompt, and dynamic variables every time.
Goal: Preserve user inputs across popup sessions using Chrome’s storage API, so values persist even when the popup is closed and reopened.
chrome.storage.local API (persistent, local-only storage)apiKey: string (API key input)userPrompt: string (simulated user prompt textarea)dynamicVariables: Array<{ key: string, value: string }> (dynamic variables rows)manifest.json)storage permission to manifest.json:
"permissions": ["activeTab", "storage"]
src/popup/popup.ts)saveState() function that:
chrome.storage.localsaveState() when:
src/popup/popup.ts)loadState() async function that:
chrome.storage.localloadState() on popup initialization (DOMContentLoaded)clearState() function that:
chrome.storage.local for the extensioninterface StoredState {
apiKey?: string;
userPrompt?: string;
dynamicVariables?: Array<{ key: string; value: string }>;
}
chrome.storage.local is acceptable for local development tools
User Flow After Phase 5:
Benefits:
Problem: Popup closes automatically when users click outside or interact with the webpage.
Solution: Migrate to Chrome’s Side Panel API for persistent UI that stays open during page interactions.
Manifest (public/manifest.json):
"sidePanel" to permissions arrayside_panel configuration pointing to popup.htmlaction to remove default_popup (keep icon configuration)background service worker configurationBackground Script (src/background/background.ts):
chrome.sidePanel.setPanelBehavior({ openPanelOnActionClick: true })Webpack (webpack.config.js):
Problem: The current output displays the entire raw JSON response, which contains too much technical metadata that users don’t need for everyday testing. While the full JSON is useful for debugging, users primarily care about the actual conversation flow between the agent and the simulated user.
Goal: Add a user-friendly conversation display section that shows a clean, readable transcript of the dialogue, while keeping the full JSON output available below for those who need it.
src/popup/popup.html) ✅<pre> element<div id="conversationTranscript">) for displaying the conversationData Source: Extract from response.simulated_conversation array
Fields to Use:
role: “agent” or “user”message: The actual message text (may be null for some turns, e.g., tool calls)Display Format:
Edge Cases Handled:
message is null (e.g., tool calls without spoken messages)src/popup/popup.css) ✅src/popup/popup.ts) ✅displayConversation() function that:
simulated_conversation array from API responsemessage is null or emptydisplayConversation() when simulation completes successfully (via displayResult())ConversationTurn, SimulationResponse)User Flow After Phase 7:
Benefits:
POST https://api.elevenlabs.io/v1/convai/agents/{agent_id}/simulate-conversationxi-api-key header with API keysimulation_specification object containing:
simulated_user_config: Configuration for the simulated user
prompt: Object with prompt (string), llm (string), temperature (number)dynamic_variables, extra_evaluation_criteria, new_turns_limit, tool_mock_configAgentSimulatedChatTestResponseModel containing:
simulated_conversation: Array of conversation turnsanalysis: Evaluation results and metrics@elevenlabs/elevenlabs-js (Node.js SDK): Cannot run in browser environments (Node.js only)@elevenlabs/client (Browser SDK): Designed for real-time voice conversations via WebSocket/WebRTC, does NOT support the simulate-conversation REST API endpoint