Save a Transcript
Persist the complete transcript after a session ends.
How to collect and persist a complete transcript after a realtime session ends.
Collecting segments
During the session, accumulate conversation.item.input_audio_transcription.completed events:
const segments = [];
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'conversation.item.input_audio_transcription.completed') {
segments.push({
utterance_index: data.utterance_index,
text: data.text,
language: data.language,
audio_duration_ms: data.audio_duration_ms,
latency_ms: data.latency_ms,
timestamp: Date.now(),
});
}
};
ws.onclose = () => {
// Session ended — save the complete transcript
saveTranscript(segments);
};
Merging into a full transcript
function mergeTranscript(segments) {
// Sort by utterance_index to ensure order
segments.sort((a, b) => a.utterance_index - b.utterance_index);
return segments.map(s => s.text).join('\n');
}
Storage format
Recommended JSON structure:
{
"session_id": "sess_...",
"started_at": "2026-08-15T10:00:00Z",
"ended_at": "2026-08-15T10:30:00Z",
"language": "zh",
"segments": [
{
"utterance_index": 0,
"text": "The weather is nice today",
"audio_duration_ms": 3200,
"latency_ms": 480
}
],
"full_text": "The weather is nice today\nIt might rain tomorrow"
}
Detecting missing segments
Check for gaps in utterance_index:
function findMissing(segments) {
const indices = segments.map(s => s.utterance_index);
const max = Math.max(...indices);
const missing = [];
for (let i = 0; i <= max; i++) {
if (!indices.includes(i)) missing.push(i);
}
return missing;
}
Missing segments may occur if frames were dropped due to backpressure or concurrent utterance limits.
Offline alternative
For cases where you need a guaranteed complete transcript, consider using the Recorded API instead — submit the recorded audio file and get the full structured result.
Related
- Transcript Lifecycle — event states
- Transcribe Audio — offline alternative
- Subtitles — subtitle generation
