The <sv-agent> widget is a web component that drops a fully working AI avatar into any web page. This guide covers everything the integration surface offers: configuration attributes, lifecycle events, and the JavaScript methods for voice and custom rendering.
All names below are verified against the current widget build. Where the console is involved (getting your Agent Profile ID, generating embed code), see the Share dialog β Embed code card described in the avatar guide.
Prerequisites
- API key or session token β one of the two is required. - The API key authenticates your widget directly. It is issued per organization; you also register the hostnames that will load the widget, and only those hosts are accepted. - A session token is a JWT you sign yourself, for teams that want to control expiry and rotation. See Session tokens below.
- Agent Profile ID β a ULID identifying which avatar and configuration to load. Copy it from the console’s embed-code screen.
Quick start
Load the SDK from the CDN, then place the component:
<script
type="module"
src="https://cdn.perxona.ai/prod/latest/widget/entry/index.js"
></script>
<sv-agent
apiKey="<YOUR_API_KEY>"
agentProfileId="<YOUR_AGENT_PROFILE_ID>"
conversationMode="inputText"
displayMode="fullPresentation"
></sv-agent>
Do not style sv-agent with your own CSS (position/transform/size overrides) β the widget manages its own layout and external CSS breaks it.
Settings can also be changed after load via JavaScript:
const widget = document.querySelector('sv-agent');
widget.updateWidgetSetting({
presentationMode: 'bubble',
conversationMode: 'inputText',
cameraAngle: 'fullBody',
});
Attribute reference
Authentication and identity:
| Attribute | Description |
|---|---|
apiKey |
Perxona API key. Keep it secret. If both apiKey and sessionToken are set, apiKey wins. |
sessionToken |
Self-managed JWT alternative to the API key (see Session tokens). |
agentProfileId |
ULID of the Agent Profile to load. Required. |
customerRefId |
Optional free-form ID linking the session to your own user record β this is what enables cross-session memory and lets you find the visitor in the console’s Conversation history. |
Layout and appearance:
| Attribute | Values | Description |
|---|---|---|
displayMode |
fullPresentation (default) / 3DPresentation / 2DPresentation |
Full widget with chat UI; 3D avatar only (you build the UI); or chat window only. |
presentationMode |
bubble / embedded |
Floating chat-bubble launcher, or embedded in the page flow. |
cameraAngle |
fullBody / halfBody |
Default framing of the 3D avatar. |
initFov |
JSON, e.g. '{"distance": 1, "horizontal": 0, "vertical": 0}' |
Camera distance and offsets. |
appearanceMode |
light / dark |
Widget color scheme. |
userBubbleColor |
CSS color | Chat-bubble accent color. |
bubbleSetting |
JSON, e.g. '{"icon": {"src": "β¦"}}' |
Bubble launcher details such as a custom icon. |
showHeader |
true (default) / false |
Whether the widget header bar is shown. |
Behavior:
| Attribute | Values | Description |
|---|---|---|
readyToShowPolicy |
showWhenAssetsLoading (default) / showWhenAssetsReady |
Show immediately with a loading indicator, or only once assets finish downloading. |
conversationMode |
inputText (default) / microphone |
Text input or voice interaction. |
muted |
true / false (default) |
Start with audio output muted. |
enableUserActivationCheck |
true (default) / false |
Wait for a real user gesture before enabling speech playback (browser autoplay rules). Set false only in controlled environments such as native WebViews that already relax autoplay β iOS WKWebView: mediaTypesRequiringUserActionForPlayback = []; Android WebView: setMediaPlaybackRequiresUserGesture(false). |
supportedFeatures |
JSON, e.g. '{"multimedia": true}' |
Optional feature toggles; multimedia (default on) shows knowledge-base media attachments in the widget. |
Events
Listen with addEventListener on the sv-agent element.
life-status β connection lifecycle. event.detail.status is one of disconnected, agent-preparation, downloading-assets, connection-start, connection-done, ready.
asset-download-status β download progress. Payload: status (always downloading-assets), asset (avatar / motion / scene), progress (0β100).
conversation-status β conversation lifecycle. event.detail.status is one of idle, user-inputting, user-input-done, awaiting-response, awaiting-response-done, rendering-response, timeout; input carries the user text where applicable.
agent-response-message β the message stream. Payload: event (user-input / agent-answer / agent-end), message, messageId (correlates a question with its answer), optional ssmlMessage, createdAt.
chat-attachment β fired when the multimedia display presents an attachment. Payload attachments[] with type (MIME: video/mp4, image/png, image/jpeg, application/pdf) and source (URL). Use it to e.g. pause your own page’s video while the avatar plays one.
widget.addEventListener('life-status', (e) => {
if (e.detail.status === 'ready') console.log('avatar ready');
});
Voice control methods
Available once the widget is ready; all are methods on the element.
| Method | Returns | Description |
|---|---|---|
startRecording() |
Promise<boolean> |
Start speech recognition. Resolves false if the microphone is denied or the speech service is unavailable. |
stopRecording() |
void |
Stop the current recognition session; safe to call anytime. |
getRecognitionStatus() |
'idle' / 'preparing' / 'recognizing' / 'unknown' |
Current recognition state. |
isRecording() |
boolean |
Whether recognition is actively listening. |
getMicrophoneVolume() |
number |
Current mic level, for volume meters. 0 when unavailable. |
Custom rendering with agentReply
In 3DPresentation mode you drive the conversation UI yourself and use agentReply to render text and animation on the avatar:
widget.agentReply({ event: 'user_input', message: 'Hi!' });
widget.agentReply({ event: 'agent_answer', message: 'Hello! How can I help?', motion_id: 'greeting' });
widget.agentReply({ event: 'agent_end' });
event values: user_input (adds the question and an answer placeholder), agent_answer (renders the reply and speaks it via TTS), agent_end (closes the exchange). motion_id picks the animation: idle, talking, listening, greeting, error, or a custom motion from your storyboard.
Session token
A session token is an HS256 JWT you sign with your organization’s secret, carrying standard iat and exp claims β so you decide how long each embed session stays valid:
{ "iat": 1516239022, "exp": 1758004103 }
Set it via the sessionToken attribute or through updateWidgetSetting. Remove the apiKey attribute when using session tokens β apiKey takes priority when both are present.
Where things connect back to the console
- The embed snippet, key management, and your Agent Profile ID live in the avatar’s Share dialog β Embed code card.
- Media attachments shown by the multimedia display are configured in the Knowledge base.
- Conversations from embedded widgets β including
customerRefIdβ appear under Conversation history.