Events

Listen to conversation, avatar, and world events from an Experience.

Overview

Register handlers on an Experience instance to observe conversation, avatar, and world activity.

Startup

ready reports that the player visuals are mounted and ready. started reports that the player-owned startup button was clicked and audio and session startup completed.

const experience = await Experience.startSession({
  experienceId: 'exp_…'
});

experience.on('ready', ({ manifest }) => {
  console.log('Player visuals ready', manifest.experience.mode);
});

experience.on('started', ({ mode }) => {
  console.log('Audio and session started in', mode, 'mode');
});

await experience.attach({ container });

ready includes the resolved manifest. started includes the experience mode. Both replay asynchronously for handlers registered after the event. The onStart option on Experience.startSession() is a convenience callback for startup completion.

Speech and transcripts

Emitted during speak() sessions, manual or automatic listening, and custom processor conversation. Partial transcript revisions include monotonic revision and optional delta. Only updates with isFinal: true commit a user message to conversation history.

experience.on('userTranscript', (update) => {
  if (!update.isFinal) {
    liveCaptionEl.textContent = update.text;
    return;
  }
  liveCaptionEl.textContent = update.text;
  commitUtterance(update.utteranceId, update.text);
});

experience.on('userSpeechStarted', () => micIndicator.classList.add('active'));
experience.on('userSpeechEnded', () => micIndicator.classList.remove('active'));
experience.on('characterSpeechStarted', (event) => {
  console.log('Speaking', event.characterId, event.text, event.source);
});

experience.on('characterSpeechEnded', (event) => {
  console.log('Speech ended', event.reason, event.durationMs);
});

experience.on('conversationUpdate', (conversation) => {
  console.log('History length', conversation.length);
});

experience.on('listeningState', (listening) => {
  console.log('Mic gate', listening);
});

Custom conversation processor

When you supply conversationProcessor on startSession(), processor failures surface as conversationProcessorError. The managed LLM is not used as a fallback.

experience.on('conversationProcessorError', ({ utteranceId, message }) => {
  console.error('Processor failed for', utteranceId, message);
  // Retry, speak a fallback line, or show host UI.
});

Conversation (managed and custom mode)

experience.on('message', (message) => {
  console.log(message.role, message.text, message.source);
});

experience.on('modeChange', (mode) => {
  // 'listening' | 'speaking' | 'thinking'
  console.log('Session mode', mode);
});

Lip-sync, expressions, and body animation run inside the hosted player. Integrators do not receive viseme or animation keyframe events — use characterSpeechStarted / characterSpeechEnded when you need to sync your UI with speech.

World

experience.on('stateUpdate', (patch) => { /* structured state change */ });
experience.on('locationChange', ({ locationId }) => { });
experience.on('characterEnter', ({ characterId }) => { });
experience.on('characterExit', ({ characterId }) => { });
experience.on('close', ({ reason, returnUrl }) => { });

Event reference

EventPayloadDescription
ready{ manifest }Player visuals are mounted and ready
started{ mode }Player startup click, audio unlock, and session startup completed
userTranscript{ utteranceId, text, revision, isFinal, delta? }Partial and final STT updates. Ephemeral until isFinal: true.
userSpeechStarted{ utteranceId? }VAD detected speech activity (auto mode telemetry)
userSpeechEnded{ utteranceId? }VAD detected end of speech; final text may arrive after this event
characterSpeechStarted{ speechId, turnId, characterId, text, source }Character began speaking (speak, opening, or llm)
characterSpeechEnded{ speechId, turnId, characterId, text, source, durationMs?, reason }Character speech finished or was interrupted
conversationUpdateConversationMessage[]Immutable snapshot of in-session conversation history
listeningStatebooleanManual listening gate opened (true) or closed (false)
messageConversationMessageDurable user or assistant message committed to session history
modeChangelistening | speaking | thinkingSession activity mode for UI sync
conversationProcessorError{ utteranceId, message }Browser conversationProcessor threw or rejected
stateUpdateState patchStructured world state change from server
close{ reason, returnUrl? }Session ended by user or programmatically