Overview
Omi’s transcription system provides real-time speech-to-text conversion with speaker identification, multiple language support, and seamless integration with the conversation processing pipeline.- Quick Start
- Full Documentation
- Key Concepts
Connect to
/v4/listen WebSocket with your user token and start streaming audio. Transcripts arrive in real-time as JSON.WebSocket Endpoint
Endpoint URL
Query Parameters
uid (required)
uid (required)
Type:
stringUser ID obtained from Firebase authentication. Required for all connections.language
language
Type:
string | Default: 'en'Language code for transcription. Supports:- Standard codes:
'en','es','fr','de','ja','zh', etc. - Multi-language:
'multi'for automatic language detection
sample_rate
sample_rate
Type:
integer | Default: 8000Audio sample rate in Hz. Common values: 8000, 16000, 44100, 48000codec
codec
Type:
string | Default: 'pcm8'Audio codec. Supported options:pcm8- 8-bit PCM (default)pcm16- 16-bit PCMopus- Opus codec (16kHz)opus_fs320- Opus with 320 frame sizeaac- AAC codeclc3- LC3 codeclc3_fs1030- LC3 with 1030 frame size
channels
channels
Type:
integer | Default: 1Number of audio channels. Use 1 for mono, 2 for stereo.include_speech_profile
include_speech_profile
Type:
boolean | Default: trueEnable speaker identification using the user’s stored speech profile. When enabled, the system extracts a speaker embedding from the user’s speech profile and uses it to identify the user’s voice via biometric matching.conversation_timeout
conversation_timeout
Type:
integer | Default: 120 | Range: 2-14400Seconds of silence before the conversation is automatically processed. After this timeout, the conversation is saved and LLM processing begins.stt_service
stt_service
Type:
string | OptionalExplicitly specify STT service. Options: deepgram. If not specified, Deepgram is used.custom_stt
custom_stt
Type:
string | Default: 'disabled'Enable custom STT mode. When set to 'enabled', the backend accepts app-provided transcripts instead of using STT services. Useful for apps with their own transcription.source
source
Type:
string | OptionalConversation source identifier. Examples: 'omi', 'openglass', 'phone'Audio Codecs
The system supports multiple audio codecs with automatic decoding:All audio is internally converted to 16-bit linear PCM before being sent to STT providers.
STT Service Selection
The selected streaming provider comes from the orderedSTT_SERVICE_MODELS
configuration. The first configured model that supports the requested language
wins. Pre-recorded voice and sync routes use the corresponding
STT_PRERECORDED_MODEL selection contract.
Provider Capabilities
Transcription outcome contract
Transport success is not transcription success. The backend uses one bounded semantic vocabulary across voice upload, voice-message SSE, offline sync, and live provider failures:POST /v2/voice-message/transcribe returns outcome alongside transcript,
stt_provider, and stt_model. True silence remains HTTP 200 with an empty
transcript and outcome=expected_silence. All failure outcomes use a non-2xx
status and a fixed response body containing only error, outcome,
provider, retryable, and a public-safe message; provider response bodies,
audio identifiers, and exception text are never exposed.
The /v2/voice-messages stream emits the same safe failure object in a terminal
error: SSE frame. A normal empty stream is reserved for explicit
expected_silence.
For /v4/listen, an unusable initial or mid-session STT socket emits this event
before the client connection closes with WebSocket code 1011:
Production transcription candidate gate
The manual backend workflow deploys a no-traffic, uniquely taggedbackend
candidate and proves the real /v2/voice-message/transcribe route before
shifting any Cloud Run traffic. The same path runs for an explicit development
deployment first, which is the required identity-and-route dry run before a
production release. The tag resolver requires the exact candidate revision
recorded in Cloud Run status.traffic; it cannot accidentally exercise the
current serving revision or latest-created revision.
backend/testing/release_fixtures/transcription-release-probe.wav and its
versioned JSON manifest provide the known audio, language, expected transcript,
SHA-256 digest, and CC-BY-4.0 LibriSpeech provenance. The gate requires HTTP
200, outcome=success, and the exact normalized transcript. It intentionally
does not assert provider or model identity: this is a semantic capability gate,
not an unreviewed routing-policy setting.
The shared transcription-release-candidate-probe action uses the existing
authenticated deploy identity to read the existing FIREBASE_API_KEY Secret
Manager secret, sign a five-minute Firebase custom token for the dedicated
non-human omi-release-probe UID, and exchange it immediately for an ID token.
It writes that token only to an owner-only temporary runner file, never exposes
it through workflow outputs or evidence, and deletes it at step exit. The
workflow makes no IAM changes: the existing deploy identity must be reviewed to
have only the Secret Manager read and iam.serviceAccounts.signJwt access this
action needs. Missing access fails closed before promotion. Reports contain only
redacted booleans and status codes.
The Cloud Run candidate itself makes the private VPC hop to Parakeet. After a
passing or failed candidate gate, the workflow removes its temporary tag; a
failed gate never shifts traffic.
Automatic development candidate acceptance
gcp_backend_auto_dev.yml keeps the development backend mutation lock while
it deploys the four Cloud Run services (backend, backend-sync,
backend-sync-backfill, and backend-integration) with the service-scoped
candidate tag. It resolves each exact tag URL from Cloud Run status, runs the
source-owned backend/deploy/dev_candidate_acceptance.json manifest, and only
then permits the one traffic-promotion step. The backend uses the authenticated
What Matters Now contract; the worker services use bounded /v1/health checks.
The evidence artifact records only service, bounded contract category, and
outcome — never URLs, tokens, user data, or response bodies.
Candidate requests carry an OIDC token in X-Serverless-Authorization while
the application keeps its own Authorization header. The token audience is
the canonical Cloud Run service URL as required by Cloud Run; the HTTP target
remains the exact no-traffic tagged candidate URL.
Development pusher is deliberately GKE-only (pusher.omiapi.com). A
legacy Cloud Run pusher service is not a deploy, candidate, or health-report
surface; do not publish an image merely to make that retired surface appear
ready.
During the direct-URL retirement window, the public dev Cloud Run backend
and legacy backend-listen services must use http://pusher.omiapi.com.
Other dev Cloud Run services and jobs must not define HOSTED_PUSHER_API_URL.
Retire those public endpoints only after they show no /v4/listen traffic.
Deepgram Configuration
When using Deepgram, the following options are configured:External Custom STT Service
Build your own transcription/diarization WebSocket service that integrates with Omi.Your Service Receives
Your Service Sends
Format: JSON object withsegments array
Segment Fields
Requirements
Speech Profile & Speaker Embedding
When a user has a speech profile, the system uses speaker embedding comparison to identify the user’s voice in real-time.
How It Works
Speech Profile Benefits
- User Identification: Speaker embedding comparison identifies the device owner by voice biometrics
- No Startup Delay: Transcription begins immediately (no profile audio prepending)
- Single Socket: One Deepgram connection per session (reduced API costs)
Transcription Flow
Connection Established
WebSocket connection accepted, user validated, STT provider selected based on language.
Audio Streaming
App sends binary audio chunks. Backend decodes based on codec parameter.
STT Processing
Decoded audio sent to Deepgram. Provider returns word-level transcripts with speaker IDs.
Segment Creation
Words grouped into segments. Same-speaker consecutive words merged. Timing adjusted for speech profile offset.
Real-time Delivery
JSON segments streamed back to app immediately. UI updates as user speaks.
Conversation Lifecycle
Background task monitors silence. After
conversation_timeout, conversation is processed and saved.Message Formats
Incoming Messages (App → Backend)
- Audio Data
- Speaker Assignment
- Custom Transcript
- Image Chunk
Format: BinaryRaw audio bytes encoded according to the Keep-alive: Messages of 2 bytes or less are treated as heartbeat pings.
codec parameter. Sent continuously during recording.Outgoing Messages (Backend → App)
- Transcript Segments
- Service Status
- Speaker Suggestion
- Conversation Created
- Translations
Format: JSON ArrayReal-time transcript segments as they’re detected:
Transcript Segment Model
Each transcript segment contains:Connection Lifecycle
Lifecycle Events
Open
- WebSocket accepted
- User authentication verified
- Language/STT service selected
- STT connections initialized (with retry logic)
- Speech profile loaded in background
- Heartbeat task started (10s interval)
Stream
- Audio received and decoded
- Sent to STT provider(s)
- Results collected in buffers
- Processed every 600ms
- Segments sent to client
- Speaker suggestions generated
Close
- Usage statistics recorded
- All STT sockets closed
- Client WebSocket closed (code 1000/1001)
- Buffers and collections cleared
Error Handling & Retry Logic
The system includes robust error handling:Key File Locations
Related Documentation
Backend Deep Dive
Complete backend architecture overview
Storing Conversations
How conversations and memories are stored
Chat System
How the AI chat system uses transcriptions
Backend Setup
Environment setup and configuration