For the complete documentation index, see llms.txt. This page is also available as Markdown.

Transcript API

Query transcript turns, subscribe to live changes, read captions, and export session history from Unity scripts using the transcript facade.

ConvaiTranscripts is the Convai Unity SDK's canonical transcript facade: a live, in-memory timeline of every player and character turn in the room, with pull-based queries, push-based change events, live captions, and a session export helper. Use this page when scripting custom chat UI, transcript export, or turn-level conversation logic. Access the facade through ConvaiManager.ActiveManager.Transcripts.


Push vs. pull

ConvaiCharacter.OnTranscriptReceived

Event relays (ConvaiTranscriptEventRelay, ConvaiEvents)

ConvaiTranscripts

Delivery

Push — plain C# event fires per update, for one character's own spoken line

Push — Inspector UnityEvents or C# events fire per update

Pull (CurrentTimeline, GetTurns) and push (Changed, Subscribe)

History

Only the current update, scoped to that character

Only the current update

Full history: active turns, committed turns, and live captions

Use cases

Character-scoped push reactions — gaze, gestures, single-character subtitles

Subtitle rendering, per-character animation triggers

Custom chat UI, post-session export, turn-level assessment logic

Access

character.OnTranscriptReceived on a ConvaiCharacter reference

ConvaiTranscriptEventRelay, ConvaiManager.ActiveManager.Events

ConvaiManager.ActiveManager.Transcripts


ConvaiCharacter.OnTranscriptReceived

OnTranscriptReceived is a plain C# event declared on ConvaiCharacter: event Action<string, bool> OnTranscriptReceived. It is the character-scoped counterpart to the ConvaiTranscripts facade below — reach for it when you already hold a reference to one ConvaiCharacter and want a direct push notification for that character's own spoken line, without subscribing to the room-wide facade or adding an event relay component.

character.OnTranscriptReceived += HandleTranscript;

private void HandleTranscript(string text, bool isFinal)
{
    if (!isFinal) return; // discard the interim delivery so the sentence is not appended twice
    _log.text += $"\n{text}";
}

The first argument is the transcript text. The second, isFinal, comes from the message's own lifecycle — a settled line reports true; a line that is still streaming reports false.

Text arrives per sentence, not per synthesis chunk. A sentence that streams before it settles is delivered twice: once with isFinal false while it is still in progress, and once more with isFinal true once it settles. A handler that appends text on every call without checking isFinal duplicates the sentence.

OnTranscriptReceived only fires for this character's own spoken output — quiet, unspoken bot text is filtered out, and the incoming message is matched to this character by participant ID first, falling back to character ID.

Use ConvaiCharacter.OnTranscriptReceived for single-character push reactions. Use ConvaiTranscripts below when you need full room history, multiple characters or players, or pull-based queries.


ConvaiTranscripts facade

ConvaiManager.ActiveManager.Transcripts throws InvalidOperationException if the SDK has not finished bootstrapping. Use manager.TryGetTranscripts(out ConvaiTranscripts transcripts) when the caller might run before initialization completes, such as OnEnable.

Properties

Member
Type
Description

CurrentTimeline

TranscriptTimeline

Current transcript timeline. Returns the same instance until the underlying engine snapshot changes.

CurrentCaptions

TranscriptCaptionSnapshot

Current live caption snapshot for speech-aligned subtitles.

IsPresentationEnabled

bool

Whether shipped presentation components should render transcript updates. Read-only; canonical history keeps recording regardless.

Events

Event
Argument
Fires when

Changed

TranscriptChangeBatch

One or more turns were added, updated, committed, interrupted, corrected, or removed

TurnUpdated

TranscriptTurn

A turn receives new text or a non-terminal state change

TurnCommitted

TranscriptTurn

A turn transitions to Committed or Interrupted

TurnCorrected

TranscriptTurn

A previously committed turn's text is corrected

TurnRemoved

string (turn ID)

A turn is removed from the timeline

CaptionsChanged

TranscriptCaptionSnapshot

The live caption snapshot changes

PresentationEnabledChanged

bool

IsPresentationEnabled changes

Methods

Method
Returns
Description

GetTurns(TranscriptQuery query = null)

IReadOnlyList<TranscriptTurn>

Returns all turns matching the optional query. Pass null for every turn.

GetTurn(string turnId)

TranscriptTurn

Retrieves a specific turn by ID. Returns null if not found.

GetLatestTurn(TranscriptParticipantRef participant)

TranscriptTurn

Returns the most recent turn for the given participant. Returns null if none.

Subscribe(Action<TranscriptChange> callback, TranscriptSubscriptionOptions options = null)

IDisposable

Registers a callback for matching turn changes. Dispose the return value to unsubscribe.

SubscribeCommitted(Action<TranscriptChange> callback, TranscriptSubscriptionOptions options = null)

IDisposable

Shortcut for Subscribe with IncludeActive = false and IncludeTerminal = true — committed and interrupted turns only.

SubscribeCaptions(Action<TranscriptCaption> callback, TranscriptCaptionSubscriptionOptions options = null)

IDisposable

Registers a callback for live caption updates.

Clear()

void

Clears the canonical transcript history.

Export(TranscriptExportFormat format)

string

Serializes every committed turn to plain text, Markdown, or JSON.

Dispose()

void

Unsubscribes from internal engine events. Call when the owning component is destroyed.


TranscriptTimeline

Property
Type
Description

Cursor

long

Monotonically increasing value that changes whenever the timeline updates

ActiveTurns

IReadOnlyList<TranscriptTurn>

Turns that are not yet committed (Listening, Streaming, or Stable)

CommittedTurns

IReadOnlyList<TranscriptTurn>

Turns in a terminal state (Committed or Interrupted)

TurnsById

IReadOnlyDictionary<string, TranscriptTurn>

All turns indexed by TranscriptTurn.Id

Turns

IReadOnlyList<TranscriptTurn>

ActiveTurns and CommittedTurns combined and ordered by RoomSequence

TranscriptTimeline.Empty is a static, reusable empty instance — a safe default before a session connects.


TranscriptTurn

Property
Type
Description

Id

string

Unique identifier for this turn

MessageId

string

Message identifier associated with this turn

ResponseId

string

Response identifier associated with this turn, when applicable

RoomSequence

long

Monotonically increasing sequence number within the room

Revision

int

Increments each time the turn's content or state changes

Speaker

TranscriptSpeaker

Who produced this turn

State

TranscriptTurnState

Current lifecycle state of this turn

PrimaryTextSource

TranscriptTextSource

Dominant text source backing this turn's display text

StableText

string

Finalized text that will not change on further updates

InterimText

string

In-progress text from the current streaming segment

DisplayText

string

Text to render for this turn — combines StableText and InterimText

StartedAtUtc

DateTime

UTC time the turn began

LastUpdatedAtUtc

DateTime

UTC time of the most recent update

CommittedAtUtc

DateTime?

UTC time the turn was committed; null while active

WasInterrupted

bool

true when the turn ended due to interruption

Segments

IReadOnlyList<TranscriptSegment>

Individual transcript segments that make up this turn

HasText

bool

true when DisplayText is non-empty

IsCommitted

bool

true when State is Committed or Interrupted

Use DisplayText for real-time rendering. It combines StableText and InterimText, so it always shows the most complete text available regardless of State.

TranscriptTurnState enum

Value
Description

Listening (0)

Turn is open and waiting for speech or text input; no text captured yet

Streaming (1)

Turn is actively receiving text; InterimText is updating

Stable (2)

Streaming has paused; text is stable but the turn is not yet committed

Committed (4)

Turn is fully committed; StableText is final

Interrupted (5)

Turn ended because it was interrupted (WasInterrupted is true)

Discarded (6)

Turn was closed with no text and excluded from both ActiveTurns and CommittedTurns


TranscriptSegment

Property
Type
Description

Id

string

Unique identifier for this segment

TurnId

string

ID of the parent TranscriptTurn

Speaker

TranscriptSpeaker

Who produced this segment

StableText

string

Finalized text for this segment

InterimText

string

In-progress text for this segment

DisplayText

string

Text to render for this segment

State

TranscriptTurnState

Lifecycle state of this segment

Source

TranscriptTextSource

Origin of this segment's text

StartedAtUtc

DateTime

UTC time this segment began

UpdatedAtUtc

DateTime

UTC time of the most recent update

StoppedAtUtc

DateTime?

UTC time this segment stopped; null while active

TranscriptTextSource enum

Value
Description

Unknown (0)

Source could not be determined

InterimAsr (1)

In-progress speech-to-text recognition

AsrFinal (2)

Finalized speech-to-text recognition

ProcessedFinal (3)

Finalized text after player-side processing

TypedText (4)

Text typed by the player rather than spoken

BotOutput (5)

Finalized character response text

BotPreview (6)

In-progress character response preview (LLM streaming)

LegacyBotTranscript (7)

Character transcript text from the legacy pipeline


TranscriptSpeaker

Property
Type
Description

Type

TranscriptSpeakerType

Whether this speaker is a Player, Character, or System

Id

string

Character ID or player ID for this speaker

DisplayName

string

Human-readable name

ParticipantId

string

Room-level participant identifier

TranscriptSpeakerType enum

Value
Description

Player (0)

A human player participant

Character (1)

An AI character participant

System (2)

A system-originated speaker, not tied to a player or character


TranscriptChange and TranscriptChangeBatch

TranscriptChange:

Property
Type
Description

Kind

TranscriptChangeKind

The kind of change this instance represents

Turn

TranscriptTurn

The affected turn; null when Kind is Removed

TurnId

string

ID of the affected turn

TranscriptChangeBatch:

Property
Type
Description

Timeline

TranscriptTimeline

Full timeline after this batch of changes

Changes

IReadOnlyList<TranscriptChange>

Every change included in this batch

ChangedTurns

IReadOnlyList<TranscriptTurn>

Convenience accessor: every non-null Turn from Changes

TranscriptChangeKind enum

Value
Description

Added (0)

A new turn was created

Updated (1)

An existing turn received new text or a non-terminal state change

Committed (2)

A turn transitioned to Committed

Interrupted (3)

A turn transitioned to Interrupted

Corrected (4)

A previously committed turn's text was corrected

Removed (5)

A turn was removed from the timeline


TranscriptQuery — filter GetTurns results

Field
Type
Default
Description

ParticipantKind

TranscriptParticipantKind?

null (all)

Filter to Player or Character turns only

PlayerOrCharacterId

string

null (all)

Filter to a specific player or character ID

ParticipantId

string

null (all)

Filter to a specific room participant ID

IncludeActiveTurns

bool

true

Include turns that are still active (not yet committed)

IncludeCommittedTurns

bool

true

Include turns that have been committed or interrupted

TranscriptQuery uses the IncludeActiveTurns/IncludeCommittedTurns field names. TranscriptSubscriptionOptions, used by Subscribe, uses IncludeActive/IncludeTerminal instead.

TranscriptParticipantKind enum

Value
Description

Player (0)

A human player participant

Character (1)

An AI character participant

TranscriptParticipantRef struct

Used as the participant argument to GetLatestTurn.

Property
Type
Description

Kind

TranscriptParticipantKind

Whether this participant is a Player or Character

PlayerOrCharacterId

string

The character ID or player ID for this participant

DisplayName

string

Human-readable name

ParticipantId

string

Room-level participant identifier

IsEmpty

bool

true when PlayerOrCharacterId is null or whitespace

Constructed with new TranscriptParticipantRef(TranscriptParticipantKind kind, string playerOrCharacterId, string displayName, string participantId = null). Implements IEquatable<TranscriptParticipantRef> and the ==/!= operators.


TranscriptSubscriptionOptions — filter Subscribe callbacks

Field
Type
Default
Description

ReplayExisting

bool

false

When true, Subscribe immediately invokes the callback for every matching turn already in CurrentTimeline

IncludeActive

bool

true

Include turns that are not yet committed

IncludeTerminal

bool

true

Include turns that are committed or interrupted

SpeakerType

TranscriptSpeakerType?

null (all)

Filter to a specific speaker type

SpeakerId

string

null (all)

Filter to a specific speaker ID

ParticipantId

string

null (all)

Filter to a specific room participant ID


Live captions

Captions are a separate, ephemeral projection of speech-aligned text — kept apart from durable chat history so ephemeral TTS preview text is never treated as canonical conversation history.

TranscriptCaption

Property
Type
Description

TurnId

string

ID of the transcript turn this caption is aligned to

Speaker

TranscriptSpeaker

Who produced this caption

Text

string

Caption text

State

TranscriptCaptionState

Current caption state

UpdatedAtUtc

DateTime

UTC time of the most recent update

HasText

bool

true when Text is non-empty

IsFinal

bool

true when State is Completed or Interrupted

WasInterrupted

bool

true when State is Interrupted

TranscriptCaptionState enum

Value
Description

Streaming (0)

Caption text is actively updating

Stable (1)

Caption text has paused updating but is not yet final

Completed (2)

Caption finished normally

Interrupted (3)

Caption ended because the turn was interrupted

TranscriptCaptionSnapshot

Property
Type
Description

Cursor

long

Monotonically increasing value that changes whenever captions update

Captions

IReadOnlyList<TranscriptCaption>

Current set of live captions

TranscriptCaptionSnapshot.Empty is a static, reusable empty instance.

TranscriptCaptionSubscriptionOptions

Field
Type
Default
Description

ReplayLatest

bool

true

When true, SubscribeCaptions immediately invokes the callback for every current matching caption

IncludeStreaming

bool

true

Include captions that are still updating

IncludeFinal

bool

true

Include captions that have completed or were interrupted

SpeakerType

TranscriptSpeakerType?

null (all)

Filter to a specific speaker type

SpeakerId

string

null (all)

Filter to a specific speaker ID

ParticipantId

string

null (all)

Filter to a specific room participant ID


Export the transcript

Export(TranscriptExportFormat format) serializes every turn in CurrentTimeline.CommittedTurns, ordered by RoomSequence, to a single string. Speaker labels fall back to Speaker.Type when Speaker.DisplayName is empty.

TranscriptExportFormat enum

Value
Description

PlainText (0)

One line per turn: speaker: text

Markdown (1)

One line per turn: **speaker:** text, with a blank line between turns

Json (2)

Indented JSON array of the committed TranscriptTurn objects


Usage examples

Example 1 — Post-session transcript export

A medical training simulation exports the full session transcript to JSON after the session ends, for supervisor review.

Example 2 — Reactive chat log that appends on commit

A corporate onboarding simulation builds a scrollable chat history that appends messages only when turns are committed — avoiding flicker from interim updates.

Example 3 — Chat history with live subtitles

An industrial safety drill replays committed chat history on enable, then keeps a subtitle line in sync with live captions — separately from the durable chat log.


Troubleshooting

Symptom
Likely Cause
Fix

ConvaiManager.ActiveManager.Transcripts throws InvalidOperationException

Accessed before the SDK finished bootstrapping

Use manager.TryGetTranscripts(out var transcripts) instead of the Transcripts property during early OnEnable or Awake

GetTurns() returns an empty list

No turns exist yet, or the query's IncludeActiveTurns is false while every current turn is still active

Omit the TranscriptQuery, or set IncludeActiveTurns = true to include in-progress turns

Subscribe callback never fires

Subscribed too late, or IncludeActive/IncludeTerminal exclude every matching turn

Subscribe before or immediately after ConnectAsync; set ReplayExisting = true to receive existing turns immediately

TranscriptTurn.StableText is empty

Turn is still Streaming or Stable — text is not stable until the turn commits

Use DisplayText for in-progress rendering, or subscribe with SubscribeCommitted

SubscribeCaptions callback never fires

IncludeStreaming/IncludeFinal or the speaker filters exclude every matching caption, or ReplayLatest is false and no new caption has arrived yet

Check IncludeStreaming, IncludeFinal, SpeakerType, SpeakerId, and ParticipantId on TranscriptCaptionSubscriptionOptions; set ReplayLatest = true to receive the current caption immediately


Next steps

For event-driven transcript reactions without querying the timeline, use ConvaiCharacterEventRelay or ConvaiTranscriptEventRelay — see Character Events. For the full character scripting API, see Character & Player API. For the complete list of facade accessors on ConvaiManager, see ConvaiManager API.

Last updated

Was this helpful?