Dialerr Embed documentation
Embed a full softphone — calls, SMS, voicemail — into your own website or app, as a floating widget or inline as a column of the page. Your agents dial from your pages; you sign them in from your backend with a minted token, so agents don't need per-seat vendor accounts or a separate login.
Keys
Create a key at dialerr.com → Settings → API Access → “Embed the toolbar on your site”. You get:
- Publishable key
pk_…— goes in your page HTML (like Stripe'spk_). Safe in client code. - Secret key
sk_…— server-side only, shown once. Lives inDIALERR_SECRETon your backend.
Restrict each key to your domains (wildcards like https://*.example.com supported). Tokens are only minted for allowlisted origins.
No dashboard needed: the CLI and MCP server can provision a key via a browser-approved device flow.
Install — script tag (recommended)
Nothing to install or run. Add before </body>; the widget runs in a sandboxed iframe served from dialerr.com:
<script src="https://dialerr.com/embed.js" data-key="pk_live_xxx"></script>
That alone works — agents sign into Dialerr inside the widget. For automatic sign-in add your token route:
<script src="https://dialerr.com/embed.js" data-key="pk_live_xxx" data-token-url="/api/dialerr/token"></script>
The tag also works with no data-key: agents then sign in inside the widget. A key is what enables automatic sign-in and the domain allowlist.
Inline mode — the dialer as part of the page
data-mode="inline" renders the full dialer (dial pad, messages, leads, calls, notifications — the same column the Dialerr dashboard shows) inside an element you own, at whatever size you give it. Nothing floats and there is no launcher. It is built for a CRM or back office where people keep the dialer open all day.
<div id="dialerr" style="width: 440px; height: 100vh;"></div>
<script src="https://dialerr.com/embed.js" data-mode="inline" data-target="#dialerr"></script>
- The slot owns the size. 440px wide is the designed width. With no height the loader sets
min-height: 600px; your CSS overrides it. data-targetis required and the element must exist when the script runs — put the script after it, or adddefer. If it is missing the loader warns in the console and falls back to the floating launcher.- Single-page apps: insert the script once, in the app shell or root layout, and keep the slot mounted across routes. Unmounting the slot removes the iframe and drops a live call.
- Sign-in works exactly as in floating mode: add
data-keyand a token route for automatic sign-in, or leave them off and agents sign in inside the panel. - Switching at runtime:
Dialerr.dock()moves a floating embed into the slot andDialerr.float()goes back. Both reload the frame, so both refuse during a live call.
Check it works: an iframe whose src starts with https://dialerr.com/dashboard?embed=inline sits inside your element; the console has no [Dialerr] lines; window.Dialerr.mode is "inline"; dialerr:ready fires on window; a call placed from the panel prompts for the microphone once and fires dialerr:call_connected then dialerr:call_ended; and window.Dialerr.startCall('+15551234567', 'Test Lead') from your page makes the panel dial.
Install — React / bundlers
npm i @dialerr/embed
import { DialerrToolbar } from '@dialerr/embed/react';
// render once near the app root:
<DialerrToolbar dataKey="pk_live_xxx" tokenUrl="/api/dialerr/token" />
Programmatic: import { init, on, startCall } from '@dialerr/embed'.
Install — CLI
npx @dialerr/cli add # no key? opens a browser to provision one
npx @dialerr/cli add --key pk_... # already have a key
npx @dialerr/cli login # provision + print keys, change nothing
Detects Next.js / Vite / CRA / plain HTML, injects the widget, scaffolds the Next.js token route,
writes .env.local. Flags: --dry-run, --framework, --token-url, --base.
The CLI only reads your project and writes local files. The secret key is never a CLI argument.
Install — MCP server (AI coding assistants)
claude mcp add dialerr -- npx -y @dialerr/mcp
{ "mcpServers": { "dialerr": { "command": "npx", "args": ["-y", "@dialerr/mcp"] } } }
Then ask your assistant to “add a phone dialer with Dialerr.” Tools:
dialerr_get_install_guide, dialerr_start_key_provisioning (gives the user a
browser link to approve — sign-in or account creation happens there), and
dialerr_check_key_provisioning (returns the keys once). The server only calls the
dialerr.com API — it reads no files and runs no commands.
Seamless sign-in — the token route
Your backend exchanges the secret key for a short-lived agent token (~30 min); the widget re-mints automatically.
// Next.js — app/api/dialerr/token/route.ts
export async function GET() {
const r = await fetch('https://dialerr.com/api/v1/embed/token', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.DIALERR_SECRET}`, 'Content-Type': 'application/json' },
body: JSON.stringify({}), // or { agentEmail: currentUser.email }
cache: 'no-store',
});
return new Response(await r.text(), { headers: { 'content-type': 'application/json' } });
}
Widget configuration
| Attribute | Meaning | Default |
|---|---|---|
data-key | Publishable key — recommended; without it agents sign in inside the widget | — |
data-surface | toolbar (compact softphone) or dialer (the full dialer: calls, messages, leads, notifications) — what the launcher opens | your account's Embedded widget setting |
data-mode | floating (launcher in the corner) or inline (the full dialer rendered inside an element you own) | floating |
data-target | CSS selector of the slot for inline mode, e.g. #dialerr | — |
data-token-url | Your mint route for seamless sign-in | none (in-widget login) |
data-position | floating: bottom-right / bottom-left | bottom-right |
data-color | floating: launcher color | #4f46e5 |
data-width / data-height | floating: panel width / max height in px | 400 / 640 (toolbar), 440 / 960 (dialer) |
data-auto-open | floating: true opens the panel on load | false |
data-base | Toolbar origin | script's origin |
JavaScript API
Dialerr.open()/close()/toggle()— floating onlyDialerr.dock(selector?)/Dialerr.float()— switch inline ↔ floating; refused while a call is upDialerr.mode—"floating"|"inline";Dialerr.inCall— booleanDialerr.startCall(phone, leadName?)Dialerr.loadLead({ phone, name, externalId })— open a lead in the panelDialerr.openTab("dialer" | "messages" | "leads" | "calls" | "notifications")Dialerr.setToken(token, userData?)Dialerr.on(event, cb)/off(event, cb)
Events (also DOM events dialerr:<event> on window):
ready, open, close, mode_changed, mode_change_refused,
call_connected, call_ended, missed_call, sms_received,
voicemail, lead_dispositioned, auth_invalid.
HTTP API
| Endpoint | Auth | Purpose |
|---|---|---|
POST /api/v1/embed/token | Bearer sk_… (server) | Mint a ~30-min agent token. Body: { agentId } or { agentEmail } (optional; falls back to the key's default agent). Origin-bound; 30/min rate limit. |
GET /api/v1/embed/config?key=pk_… | public | Validate a key → { name, orgName, allowedOrigins }. |
POST /api/v1/embed/device/code | none | Start device flow → { deviceCode, userCode, verificationUriComplete, … } (10-min expiry). |
POST /api/v1/embed/device/token | none | Poll with { deviceCode } → pending, then once: { publicKey, secretKey }. 410 after claim/expiry. |
Security
sk_only in a server env var.pk_is fine anywhere.- Your site must be HTTPS (or localhost) — WebRTC microphone requirement.
- Restrict keys to your domains before production; revoke anytime in Settings → API Access.
- Minted tokens expire in ~30 minutes and are origin-bound.
Troubleshooting
- No mic prompt → page isn't HTTPS, or a restrictive
Permissions-Policyblocks iframe microphone. - 403 “not authorized for this key” → add the site's origin to the key's allowed domains.
- auth_invalid → your token route is failing; check
DIALERR_SECRETserver-side. - 410 from device/token → the 10-minute window passed or keys already claimed; restart the flow.
- Asked for inline, got a corner launcher →
data-targetis missing or its element didn't exist when the script ran. Move the script below the element or adddefer. - Inline panel is invisible → the slot has no height; give it one.
- Dialer vanished after navigating → your router unmounted the slot or the script; mount both in the app shell.
- Your site sends a Content-Security-Policy →
script-src,frame-srcandconnect-srcmust includehttps://dialerr.com.
AI assistant? The machine-readable version of this page is dialerr.com/llms.txt — it contains everything needed to complete an install end-to-end.