Publish
- Open Agents, choose an Agent, then open Website & phone.
- Add every exact website origin that may host the widget, for example
https://www.example.com. Production origins must use HTTPS. - Choose the launcher, position, colors, labels, and branding.
- Publish and copy the generated snippet:
Security model
On page load, v11 resolves only safe display configuration. When a visitor starts a call, PyAI checks the exact browserOrigin, the widget and Agent
status, account credit, and daily widget/IP limits. It then mints one
short-lived key with only omni:session, concurrency 1, the visitor origin,
and the Agent as its session label. The browser never receives a long-lived
credential.
If recording is enabled on the Agent, the widget shows the Agent’s consent
notice before requesting microphone permission.
Runtime errors
Listen forpyai:widget-error. Its detail is a stable, sanitized object:
mic_permission_denied, unsupported_browser,
origin_not_allowed, credit_exhausted, daily_cap_exceeded,
session_unavailable, websocket_failed, config_unavailable, and
consent_required. Error events never include session tokens, internal
identifiers, upstream responses, or visitor addresses.
Listen for pyai:widget:transcript to receive the same sanitized transcript
rows shown in the widget. The current public capability is
capabilities.transcript: "caller": production emits caller text only, so the
widget never fabricates Agent text from audio. detail.version is 1; its
fields are role, text, and final. Partial caller updates replace one open
row and freeze once at the response boundary. A future runtime can advertise a
broader transcript capability without changing this versioned event envelope.
Listen for pyai:widget:state to receive semantic listening, thinking, and
agent_speaking transitions derived from session controls and response audio.
Neither event nor the UI exposes raw frames, tool arguments, tokens, or
identifiers.
For a strict Content Security Policy, allow the versioned script from
https://cdn.pyai.com, API requests to https://api.pyai.com, and voice
WebSockets to wss://api.pyai.com. The runtime does not evaluate strings as
code or inject customer-provided HTML. If your policy requires nonces for
inline styles, put a nonce on the script element; v11 copies it to its style
element.
Opening audio and older embeds
Widget v11 keeps the consent line and turn-0 greeting isolated from browser speaker echo. It buffers server PCM until the playback graph is running, sends real-time digital silence instead of microphone/self-audio through the opening drain, and restores normal barge-in on later replies. Versioned widget URLs are immutable. Existing v1-v10 embeds do not update in place. Replace their script URL with/widget/v11/pyai-widget.js; v11 is the
certified, published widget (since 2026-08-24).
v11 retains protected opening and browser-valid closes,
and narrowly normalizes the deployed playback-position advisory while older
engine revisions drain. If you operate your own session broker or media UI, follow the
browser voice agent guide and mint a short-lived,
origin-locked session token with POST /v1/omni/sessions. Never put a secret
key in browser code.
The hosted widget supports the same safe declarative launcher variants and URL,
telephone, and event actions. It never evaluates custom JavaScript or HTML.