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.

KeyTypeDescription
autoOpenbooleanDefault false (show a launcher bubble). true → boot and open the widget on load.
endUserIdstringYour stable id for the visitor. Defaults to a UUID persisted in localStorage. Powers per-visitor history and rate-limit caps.
sessionIdstring (GUID)Resume an existing /v1/chat conversation. Must be a GUID issued by the API, else it's ignored.
identityTokenstringHost-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.
metadataobjectArbitrary host context (plan, role, page…). Strings/numbers/booleans, capped (≤20 keys, value ≤255 chars). Untrusted — context + console only, never identity.
hideDefaultLauncherbooleanDon't render the built-in launcher; open the widget from your own UI instead.
customLauncherSelectorstringCSS 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(): boolean

Whether 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 | null

The running conversation's session_id (null until onSessionStarted). Pass to POST /v1/chat for continuity.

dispose(): Promise

Tear the widget down and remove its mount.

reload(): Promise

Dispose and re-inject the loader.

Control (after the engine loads)

Session

getAppState(): string

loading | 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.

onSessionStarted: (id: string) => void

The WebSocket session is live; id is the conversation's session_id.

onLifecycleChanged: (state) => void

Widget lifecycle transitions (active / hidden / disposed / error).

onAppStateChanged: (state) => void

Persona app state (loading → live → …).

onError: (error | null) => void

Runtime error detail; null when cleared.

onChatUpdated: (msg) => void

A chat message arrived.

onChatCardsReceived: ({ turn_index, cards }) => void

Knowledge cards for a turn.

onLiveEntered / onLiveStateChanged: → void

Persona goes live / live flips during mode transitions.

onQueueStateChanged: (position, eta) => void

Queue position updates.

onConsentStarted / onPersonaInfo: → void

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>