Skip to main content
The hosted website widget connects visitors to a saved PyAI Agent without putting an API key in your site or requiring you to run a token server.

Publish

  1. Open Agents, choose an Agent, then open Connect → Website.
  2. Add every exact website origin that may host the widget, for example https://www.example.com. Production origins must use HTTPS.
  3. Choose the launcher, position, colors, labels, and branding.
  4. Publish and copy the generated snippet:
The widget id is an opaque public identifier. It is not an organization, project, Agent, or key id.

Security model

On page load, v7 resolves only safe display configuration. When a visitor starts a call, PyAI checks the exact browser Origin, 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 for pyai:widget-error. Its detail is a stable, sanitized object:
Supported codes are 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; v7 copies it to its style element.

Advanced integration

Use widget v3 when you operate your own session broker and need runtime configuration from your application. Your backend must call POST /v1/omni/sessions; do not use publishable or secret keys in browser voice code. The hosted widget supports the same safe declarative launcher variants and URL, telephone, and event actions. It never evaluates custom JavaScript or HTML.