Listen Once Capture
Automatic end-of-speech capture for host-owned turn loops.
When to use this pattern
Use listenOnce() when your app owns the turn loop but you want automatic end-of-speech
detection instead of Start/Stop buttons. Good fits: short quiz answers, voice form fields, booking
intake, or presenter sessions where the avatar asks a question and waits for one reply.
For deliberate pauses mid-utterance (reading practice, long rehearsal), use manual startListening() / stopListening() instead — see Guided Scripted Practice.
Requirements
speechInputMode: 'auto'onExperience.startSession()attach()completed andstartedevent fired- Only one active
listenOnce()at a time
Basic flow
const experience = await Experience.startSession({
experienceId: 'exp_01DEMO1SPANISHCAFE',
mode: 'presenter',
speechInputMode: 'auto'
});
experience.on('started', async () => {
await experience.speak({ text: 'What is your party size?' });
const answer = await experience.listenOnce({ timeoutMs: 15_000 });
console.log(answer.utteranceId, answer.text);
});
await experience.attach({ container: '#avatar' }); Quiz coach loop
Combine speak() and listenOnce() for a simple question-and-answer loop.
Grade on the host; feedback stays in your UI unless you call speak() again.
async function runQuizQuestion(question, expectedKeyword) {
await experience.speak({ text: question });
const answer = await experience.listenOnce({ timeoutMs: 20_000 });
const correct = answer.text.toLowerCase().includes(expectedKeyword);
await experience.speak({
text: correct ? 'Correct!' : 'Not quite — try the next one.',
behavior: 'interrupt'
});
} Options and failures
| Option | Behavior |
|---|---|
timeoutMs | Reject if no finalized utterance within the window (default 30 seconds) |
signal | Abort the wait; rejects with AbortError |
Timeout, abort, and permission failures reject without adding a final user message to conversation history.
Events vs listenOnce()
userSpeechStarted and userSpeechEnded are ambient VAD telemetry — useful
for mic indicators. listenOnce() is a scoped promise that resolves with finalized
text when your code is explicitly waiting for one answer. You can use both: events for UI, listenOnce() for turn logic.
For live captions while the user speaks, subscribe to userTranscript with partial
revisions — see Events.
Custom processor alternative
If Liforma should orchestrate listen → respond → speak automatically after every user utterance,
use conversationProcessor instead of hand-writing listenOnce() loops. See Custom Conversation Processor.