Integrates ElevenLabs Conversational AI with Frappe, enabling real-time two-way voice conversations with AI agents directly from your Frappe application.
- 🎙️ Real-time Voice Calls - Talk to AI agents using WebRTC
- 🎯 Multiple Agents - Configure and manage multiple ElevenLabs agents
- 🖥️ Modern Vue 3 SPA - Beautiful, responsive voice interface
- 🔗 Frappe Integration - Launch calls directly from agent records
- 🔐 Secure - API keys stored encrypted, tokens are short-lived
- 📱 Mobile-Friendly - Works on desktop and mobile browsers
- Backend: Frappe (Python)
- Frontend: Vue 3 + Vite + Tailwind CSS
- Voice SDK: @elevenlabs/client (WebRTC)
- Routing: Vue Router (clean URLs)
- Frappe framework installed
- Node.js and Yarn
- ElevenLabs account with API key
cd /path/to/your/bench
bench new-site mysite.local
bench use mysite.local# Clone from GitHub
bench get-app elevenlabs https://github.com/esafwan/frappe_elevenlabs.git --branch developOr if you have the app locally:
bench get-app elevenlabs /path/to/elevenlabsbench --site mysite.local install-app elevenlabsbench startYour app is now installed! 🎉
-
Access Frappe Desk:
http://localhost:8000/desk -
Navigate to EL Provider Settings:
- Search for "EL Provider Settings" in the awesome bar (Ctrl+K)
- Or go directly:
http://localhost:8000/app/el-provider-settings
-
Add your API Key:
- Get your API key from ElevenLabs Dashboard
- Paste it in the API Key field
- (Optional) Set Base URL if using a custom endpoint
- Click Save
Note: The API key is stored encrypted in the database for security.
-
Navigate to EL Agent List:
- Search for "EL Agent" in the awesome bar
- Or go directly:
http://localhost:8000/app/el-agent - Click New
-
Configure the Agent:
- Agent Name:
FirstChapter(used in URLs, must be unique) - ElevenLabs Agent ID: Get this from your ElevenLabs Agents page
- Example:
agent_2301k75k200zfvc9awgvrcdfk50g
- Example:
- Click Save
- Agent Name:
-
Test Configuration:
- You should see a green status indicator if everything is configured correctly
- Open any EL Agent record in Desk
- Click Actions → Open Voice Page
- New tab opens with the voice interface
- Click "Start Call" to begin talking to the AI agent
Navigate directly to the voice interface using the URL format:
http://localhost:8000/voice/{agent-name}
Examples:
http://localhost:8000/voice/FirstChapter
http://localhost:8000/voice/CustomerSupport
http://localhost:8000/voice/MyAgent
You can embed or link to the voice interface from:
- Portal pages
- Website pages
- Custom web templates
- Email links
- Load the page with an agent parameter
- Click "Start Call" button
- Allow microphone access when prompted
- Start speaking - the AI will respond in real-time
- Mute/Unmute: Click the microphone button
- View Timer: Shows call duration in MM:SS format
- Status Indicator: Shows "Listening..." when active
- End Call: Click the red phone button
| State | Description | UI Indicator |
|---|---|---|
| Idle | Ready to start | Green "Available" badge |
| Connecting | Establishing connection | Spinner + "Connecting..." |
| Active | Call in progress | Red "In Call" badge, timer running |
| Error | Connection failed | Error message displayed |
/voice → SPA entry point (shows warning if no agent)
/voice/AgentName → Load specific agent and start interface
| Endpoint | Method | Purpose | Auth |
|---|---|---|---|
/api/method/elevenlabs.api.get_agent_signed_url |
GET | Load agent metadata | Guest allowed |
/api/method/elevenlabs.api.get_webrtc_token |
GET | Get signed WebSocket URL | Guest allowed |
1. User opens /voice/FirstChapter
↓
2. Vue app loads agent metadata from Frappe DB
↓
3. User clicks "Start Call"
↓
4. Backend fetches signed URL from ElevenLabs
↓
5. Frontend connects to ElevenLabs via WebRTC
↓
6. Voice conversation starts
Stores ElevenLabs API configuration:
- API Key (Password, encrypted)
- Base URL (optional, defaults to
https://api.elevenlabs.io)
Represents a configured voice agent:
- Agent Name (unique identifier)
- ElevenLabs Agent ID (from ElevenLabs dashboard)
Planned for storing call history and analytics.
elevenlabs/
├── frontend/ # Vue 3 SPA
│ ├── src/
│ │ ├── pages/
│ │ │ └── Call.vue # Main voice interface
│ │ ├── router.js # Vue Router config
│ │ └── main.js # App entry
│ ├── vite.config.js # Vite configuration
│ └── package.json # Frontend dependencies
│
└── elevenlabs/ # Frappe app
├── api.py # Backend API endpoints
├── hooks.py # Frappe hooks
├── public/
│ └── js/
│ └── el_agent.js # Custom button script
└── www/
├── voice.html # SPA entry (generated)
└── voice.py # Page handler
# Development mode (hot reload)
cd /path/to/bench/apps/elevenlabs
yarn dev
# Production build
yarn build
# After building, restart bench
cd /path/to/bench
bench restart- Modify Vue components in
frontend/src/ - Build frontend:
yarn build - Clear cache:
bench clear-cache - Restart:
bench restart
Solution: Configure the API key in EL Provider Settings:
Desk → EL Provider Settings → Add API Key → Save
Causes:
- Agent doesn't exist in database
- Wrong agent name in URL
Solution:
- Check agent exists:
Desk → EL Agent → {agent-name} - Verify agent name matches URL parameter exactly
Causes:
- Invalid API key
- Invalid agent ID
- Network/firewall issues
Solution:
- Verify API key in EL Provider Settings
- Check agent ID is correct in EL Agent record
- Check error logs:
Desk → Error Log
Solution:
- Allow microphone access when prompted
- Check browser settings for microphone permissions
- HTTPS required in production (localhost OK for dev)
Solution:
# Rebuild and clear cache
cd /path/to/bench
bench build --app elevenlabs
bench clear-cache
bench restartCheck:
- Microphone is not muted (check icon)
- Browser has microphone permission
- Correct microphone selected in browser settings
- No other app is using the microphone
| Browser | Status | Notes |
|---|---|---|
| Chrome/Edge (Chromium) | ✅ Fully supported | Recommended |
| Firefox | ✅ Fully supported | |
| Safari (macOS/iOS) | ✅ Supported | Test on Apple devices |
| Internet Explorer 11 | ❌ Not supported | No WebRTC support |
- Stored encrypted in database using Frappe's Password field
- Never exposed to frontend
- Retrieved server-side only
- Short-lived (~1 minute)
- Single-use signed URLs
- Fetched fresh for each call
- Voice interface allows guest access
- Consider adding authentication for production
- Rate limiting recommended
- Configure production API key
- Test on production domain with HTTPS
- Verify all agents are configured
- Test on multiple browsers
- Test on mobile devices
- Set up error monitoring
- Configure rate limiting (if needed)
- Enable SSL/HTTPS (required for microphone access)
Development: Works with localhost (no HTTPS needed)
Production: HTTPS required for:
- Microphone access (getUserMedia API)
- WebRTC connections
- Service workers (future)
This app uses pre-commit for code formatting and linting:
cd apps/elevenlabs
pre-commit installTools configured:
- ruff - Python linting
- pyupgrade - Python syntax upgrades
- eslint - JavaScript linting
- prettier - Code formatting
- Python: Follow Frappe conventions
- JavaScript/Vue: Use Composition API, async/await
- CSS: Tailwind utility classes
- Commits: Descriptive, conventional commits
- ElevenLabs Dashboard: https://elevenlabs.io/app
- API Documentation: https://elevenlabs.io/docs/api-reference
- Frappe Framework: https://frappeframework.com/docs
- GitHub Repository: https://github.com/esafwan/frappe_elevenlabs
For issues or questions:
- Check the troubleshooting section above
- Review error logs:
Desk → Error Log - Check browser console (F12) for frontend errors
- Open an issue on GitHub
AGPL-3.0
# Installation
bench get-app elevenlabs https://github.com/esafwan/frappe_elevenlabs.git
bench --site mysite install-app elevenlabs
# Development
cd apps/elevenlabs
yarn dev # Frontend dev server
yarn build # Production build
bench restart # Restart backend
# Access
http://localhost:8000/desk # Frappe Desk
http://localhost:8000/app/el-provider-settings # Configure API
http://localhost:8000/app/el-agent # Manage agents
http://localhost:8000/voice/AgentName # Voice interfaceBuilt with ❤️ using Frappe Framework and ElevenLabs Conversational AI