Live Persona (3D)
Add the embodied 3D persona — voice and avatar — to any site with one line. No build step, no container element; live.js self-mounts a floating launcher and boots the 3D engine on first open.
<script src="https://cdn.personaizer.com/live.js?k=YOUR_PERSONA_ID" async></script>The ?k= value is your persona's public Persona ID, copied from the editor under Publish → Deploy — safe to expose, origin-bound to your allowed domains (see Authentication). Everything below customizes and controls that one line.
The look is the persona itself. Avatar, environment and window theme come from the persona's Design settings (flip the scene at runtime with setTheme()) — so there's no theme/accentColor on the embed line. Want a text-only bubble instead? See the Chat Persona.
Configuration
Set window.PersonAIzerConfig before the loader script. All keys are optional.
| Key | Type | Description |
|---|---|---|
| autoOpen | boolean | Default false (show a launcher bubble). true → boot and open the widget on load. |
| endUserId | string | Your stable id for the visitor. Defaults to a UUID persisted in localStorage. Powers per-visitor history and rate-limit caps. |
| sessionId | string (GUID) | Resume an existing /v1/chat conversation. Must be a GUID issued by the API, else it's ignored. |
| identityToken | string | Host-signed end-user JWT to recognize a logged-in visitor across devices. See Authentication. |
| identityTokenProvider | () => Promise<string> | Async alternative to identityToken — called to fetch/refresh the JWT when it expires. |
| position | "left" | "right" | Which side the launcher and panel sit on. Default "right". |
| userAttributes | { name?, email?, phone? } | Reserved visitor fields (scalars) — shown in the operator console and given to the persona as context. Unverified; identity comes from identityToken. |
| metadata | object | Arbitrary host context (plan, role, page…). Strings/numbers/booleans, capped (≤20 keys, value ≤255 chars). Untrusted — context + console only, never identity. |
| hideDefaultLauncher | boolean | Don't render the built-in launcher; open the widget from your own UI instead. |
| customLauncherSelector | string | CSS selector for your own element; clicking it opens the widget (no JS needed). |
<!-- Set config BEFORE the loader script -->
<script>
window.PersonAIzerConfig = {
autoOpen: true, // open immediately instead of showing a launcher
position: "right", // "left" | "right"
endUserId: "visitor-3812", // your stable visitor id (optional)
userAttributes: { name: "Jane Doe", email: "jane@acme.com", phone: "+1 555 0100" },
metadata: { plan: "pro", page: location.pathname }, // host context for the persona + console
// identityToken: "<jwt>", // recognize your logged-in user (signed server-side)
};
</script>
<script src="https://cdn.personaizer.com/live.js?k=YOUR_PERSONA_ID" async></script>Control API — window.PersonAIzer
live.js exposes the loader/lifecycle methods immediately. The full control API below is added once the 3D engine finishes loading — gate calls on getAppState() === "live" or the onLiveEntered callback.
Lifecycle (available immediately)
open()Show the panel (boots the engine on first open).
close()Hide the panel; the engine soft-pauses.
isOpen(): booleanWhether the panel is open.
hide()Hide the whole widget (launcher + panel); stays loaded, paused.
show()Restore a hidden widget.
getLifecycleState(): string"idle" | "loading" | "active" | "hidden" | "disposing" | "disposed" | "error".
getSessionId(): string | nullThe running conversation's session_id (null until onSessionStarted). Pass to POST /v1/chat for continuity.
dispose(): PromiseTear the widget down and remove its mount.
reload(): PromiseDispose and re-inject the loader.
Control (after the engine loads)
Session
getAppState(): stringloading | queue | initializing | standby | consent | live | error.
startSession()Begin the backend session from a user gesture (also unlocks audio).
enterStandby(text?) / exitStandby()Pause / resume a session (soft on WebGL — memory preserved).
Conversation
sendSystemMessage(message, triggerResponse?)Inject a system message; persona responds unless triggerResponse is false.
sendTextMessage(message)Send a user message programmatically.
getChatHistory(count?)Recent messages.
Window
setTheme("dark" | "light") / getTheme()Theme control.
setVolume(0–1) / getVolume()Speech volume.
setFullscreen(bool) / isFullscreen()Fullscreen.
Devices
requestPermission("microphone" | "camera")Prompt for device access.
getDevices(type) / setDevice(type, name|null) / getSelectedDevice(type)Enumerate and select; null = off/mute.
Other
setEnvironment(settings) / getEnvironment()Background and lighting.
acceptConsent() / sendInteraction(elementId)Consent + built-in element clicks.
Callbacks
Assign these on window.PersonAIzer before the loader script — they survive the engine boot.
The WebSocket session is live; id is the conversation's session_id.
Widget lifecycle transitions (active / hidden / disposed / error).
Persona app state (loading → live → …).
Runtime error detail; null when cleared.
A chat message arrived.
Knowledge cards for a turn.
Persona goes live / live flips during mode transitions.
Queue position updates.
Consent prompt begins / persona name + render URLs.
<script>
// Register callbacks BEFORE the loader script; they survive boot.
window.PersonAIzer = {
onSessionStarted: (id) => console.log("session", id),
onLifecycleChanged: (s) => console.log("lifecycle", s), // active | hidden | disposed …
onAppStateChanged: (s) => console.log("app", s), // loading | live | error …
onError: (e) => console.warn("widget error", e),
};
</script>
<script src="https://cdn.personaizer.com/live.js?k=YOUR_PERSONA_ID" async></script>