A live, word-timed record of the conversation — rendered as captions, read as data, or both.
Turn the transcript on and the SDK assembles both sides of the conversation as it happens: the user's speech as it is recognised, and the avatar's as it is spoken. You get a built-in caption overlay for free, and the underlying data if you want to draw your own.
Off is genuinely off. Without enabled: true no transcript is assembled at
all — useAvatar().transcript stays empty and the transcript event never
fires. It is not a hidden buffer you can reach into later.
| Prop | Type | Default | Description |
|---|---|---|---|
transcript.enabledRequired | boolean | No default | Assemble the transcript. Nothing below applies until this is true. |
transcript.captionsOptional | boolean | true | Render the built-in caption overlay. Set false to keep the data and draw your own UI. |
transcript.positionOptional | CaptionPosition | "bottom-center" | Where the overlay anchors: top-left, top-center, top-right, bottom-left, bottom-center, bottom-right. The bottom anchors lift clear of the controls bar when it is on screen. |
transcript.maxEntriesOptional | number | 50 | How many lines to retain. Older lines fall off the front. |
The common case: you want captions on screen and nothing else. One line of config, and the overlay handles its own positioning, growth, and clearing.
Style it with the Avatar props rather than fighting the overlay's own CSS:
useAvatar().transcript is the full list, oldest first. Set
captions: false to suppress the built-in overlay while keeping it.
| Field | Notes |
|---|---|
id | Stable for the life of the line. A line is rewritten in place as it grows, so key your list on this — not on the index. |
isFinal | False while the line is still growing (interim speech recognition, or an in-flight utterance). True once it is closed and will not change again. |
turnId | Groups a user line and the avatar's reply into one exchange. |
words | Word-level timings. Avatar words carry real timings from the speech alignment; user words do not — their speech was already said by the time recognition landed, so those timings are not meaningful. |
createdAt | When the line was first created, as a millisecond timestamp. |
Lines mutate. An entry is rewritten in place while it grows, then closed
with isFinal. Render off entry.id and treat the array as a snapshot — do
not accumulate it yourself, or interim text will pile up as duplicates.
The transcript event re-emits the whole list on every change. Use it for
side effects — logging, saving, scrolling — and use the state for rendering.
Filtering on isFinal is usually what you want when persisting. Interim lines
are provisional by definition and will be replaced.
Respect prefers-reduced-motion before using behavior: "smooth" — a panel
that animates on every interim word is exactly the kind of motion the setting
exists to suppress.
Captions are an accessibility feature, so treat them as one:
aria-live="polite" so a screen reader announces new final lines without
interrupting itself on every interim update.The transcript is assembled from data the session already produces — turning it on does not add a recognition pass or change what you are billed for.
It does mean the conversation exists as text in your app's memory, and anywhere you choose to send it. If you persist it, that is your record to disclose and retain, and the SDK has no part in it.