Skip to main content
layercode-js-sdk.

LayercodeClient

The LayercodeClient is the core client for all JavaScript frontend SDKs, providing audio recording, playback, and real-time communication with the Layercode agent.

Usage Example

Call connect() to start the session once the user is ready, and invoke disconnect() when you want to tear the connection down.

Constructor Options

object
required
Options for the LayercodeClient.
string
required
The ID of your Layercode agent.
string
The conversation ID to resume a previous conversation (optional).
string
required
The endpoint to authorize the session. It must return a JSON object: .
object
Optional metadata to send with the session authorization request.
boolean
Whether microphone capture should start immediately. Defaults to true. Set to false to initialize the client in text-only mode and defer the permission prompt.
boolean
Whether agent audio should play through the browser immediately. Defaults to true. Set to false to keep the connection active while holding back speaker playback until you opt in.
boolean
Whether microphone and speaker amplitude monitoring should run. Defaults to true. Disable this when audioInput starts as false to avoid unnecessary audio processing.
boolean
Whether to initialize the client-side VAD model. Defaults to true. Set to false to skip loading the VAD model, reducing CPU/memory usage at the cost of local speech detection.
number
Milliseconds before resuming agent audio after a temporary pause due to a false interruption. Defaults to 500.
function
Callback triggered when the audio input state changes. Receives a boolean.
function
Callback triggered when the audio output state changes. Receives a boolean indicating whether the agent audio is audible.
function
Callback when the client connects. Receives . Use config to inspect the effective agent configuration returned from authorizeSessionEndpoint.
function
Callback when the client disconnects.
function
Callback when an error occurs. Receives an Error object.
function
Callback for all non-audio messages from the server (excludes response.audio).
function
Callback for custom data messages from the server (typically response.data events).
function
Callback for changes in the user’s microphone amplitude (number, 0–1).
function
Callback for changes in the agent’s audio amplitude (number, 0–1).
function
Callback when the client’s status changes. Receives a string: “disconnected” | “connecting” | “connected” | “error”.
function
Callback when the SDK detects user speech start/stop. Receives a boolean.
function
Callback when the agent starts or stops speaking. Receives a boolean.
function
Callback when the client is muted or unmuted. Receives a boolean representing the new muted state.
function
Callback when the active input device changes in the browser. Receives the active deviceId.
function
Callback when available input devices change (hot-plug). Receives .

Client-side VAD (enableVAD)

When enableVAD is set to false, the client skips loading and initializing the VAD (Voice Activity Detection) model. This reduces client-side CPU/memory usage, but the client will not detect speech locally. When to use it Only disable client-side VAD when your transcription model includes built-in turn-taking (for example, Deepgram Flux) and you rely entirely on server-side speech detection. Disabling VAD otherwise removes local speech detection.
  • Performance optimization: Reduce bundle size and CPU usage on low-powered devices.
  • Custom VAD: You implement your own speech detection logic.
Behavior
  • When true (default): The VAD model loads on connect(), detects speech locally, and sends vad_start/vad_end events.
  • When false: The VAD model is not loaded, local speech detection is disabled, and you avoid the ~2MB VAD bundle overhead.

Methods

function
required
connect(): Promise<void> Connects to the Layercode agent, authorizes the session, and starts audio capture and playback.
function
required
disconnect(): Promise<void> Disconnects from the Layercode agent, stops audio capture and playback, and closes the WebSocket.
function
setAudioInput(state: boolean): Promise<void> Enables or disables microphone capture without tearing down the WebSocket. Pass true when the user opts into voice mode; pass false to drop back to text-only mode.
function
setAudioOutput(state: boolean): Promise<void> Enables or disables local agent playback without interrupting the active session.
Tip: Call setAudioOutput(false) to silence agent audio while another clip plays in your UI, then restore playback with setAudioOutput(true) when you’re ready. Pair this with the audioOutputChanged callback to keep toggles in sync.
function
setInputDevice(deviceId: string): Promise<void> Switches the microphone input. Pass ‘default’ (or an empty string) to use the system default device.
function
Returns available input devices, marking the default one.
function
getStream(): MediaStream | null Returns the active microphone MediaStream, or null if not initialized.
function
mute(): void Stop sending mic audio to the server without tearing down the stream/connection.
function
unmute(): void Resume sending mic audio to the server.

Turn-taking (Push-to-Talk)

Layercode supports both automatic and push-to-talk turn-taking. For push-to-talk, use these methods to signal when the user starts and stops speaking:
function
triggerUserTurnStarted(): Promise<void> Signals that the user has started speaking (for push-to-talk mode). Interrupts any agent audio playback.
function
triggerUserTurnFinished(): Promise<void> Signals that the user has finished speaking (for push-to-talk mode).

Text messages

function
sendClientResponseText(text: string): Promise<void> Ends the active user turn, interrupts agent playback, and forwards text to the agent. The server will emit user.transcript before the agent responds, keeping UI components in sync.
function
sendClientResponseData(payload: Record<string, any>): void Sends a JSON-serializable payload to your agent backend without affecting the current turn. The data surfaces as a data webhook event. See docs page: Send JSON data from the client.

Events & Callbacks

Properties

string
Connection status: “disconnected” | “connecting” | “connected” | “error”.
boolean
Indicates whether microphone capture is currently enabled.
boolean
Indicates whether agent audio playback is currently enabled for this client.
boolean
Whether the voice activity detector currently hears the user speaking.
boolean
Whether the agent is presently speaking (based on audio replay).
number
User mic amplitude (0–1). Non-zero only when amplitude monitoring is enabled.
number
Agent playback amplitude (0–1). Non-zero only when amplitude monitoring is enabled.
boolean
Whether the microphone track is muted.
string
The conversation ID the client is currently attached to, if any.

Agent Config (from authorizeSessionEndpoint)

On onConnect, you receive { conversationId, config }. Relevant fields:
When transcription.trigger === 'automatic' and vad.enabled !== false, the SDK initializes MicVAD and gates mic audio accordingly. gate_audio controls whether audio is sent only while speaking; buffer_frames controls the “pre-speech” buffer flushed when speech starts.

Notes & Best Practices

  • The SDK manages microphone access, audio streaming, and playback automatically.
  • Use audioInput: false plus setAudioInput(true) to defer the browser permission prompt until the user explicitly switches to voice. Disable amplitude monitoring at the same time to avoid unnecessary processing.
  • The metadata option allows you to set custom data which is then passed to your backend webhook (useful for user/session tracking).
  • The conversationId can be used to resume a previous conversation, or omitted to start a new one.

Small device example

Authorizing Sessions

To connect a client (browser) to your Layercode voice agent, you must first authorize the session. The SDK will automatically send a POST request to the path (or url if your backend is on a different domain) passed in the authorizeSessionEndpoint option. In this endpoint, you will need to call the Layercode REST API to generate a client_session_key and conversation_id (if it’s a new conversation).
If your backend is on a different domain, set authorizeSessionEndpoint to the full URL (e.g., https://your-backend.com/api/authorize).
Why is this required? Your Layercode API key should never be exposed to the frontend. Instead, your backend acts as a secure proxy: it receives the frontend’s request, then calls the Layercode authorization API using your secret API key, and finally returns the client_session_key to the frontend. This also allows you to authenticate your user, and set any additional metadata that you want passed to your backend webhook. How it works:
  1. Frontend: The SDK automatically sends a POST request to your authorizeSessionEndpoint with a request body.
  2. Your Backend: Your backend receives this request, then makes a POST request to the Layercode REST API /v1/agents/web/authorize_session endpoint, including your LAYERCODE_API_KEY as a Bearer token in the headers.
  3. Layercode: Layercode responds with a client_session_key (and a conversation_id), which your backend returns to the frontend.
  4. Frontend: The SDK uses the client_session_key to establish a secure WebSocket connection to Layercode.
Example backend authorization endpoint code:

Custom Authorization

Use the optional authorizeSessionRequest function when you need to control how authorization credentials are exchanged with your backend (for example, to add custom headers or reuse an existing HTTP client).
Custom Authorization example
If you omit authorizeSessionRequest, the client falls back to a standard fetch call that POSTs the JSON body to authorizeSessionEndpoint.

Request payload

  • agent_id – ID of the agent to connect.
  • metadata – metadata supplied when instantiating the client.
  • sdk_version – version string of the JavaScript SDK.
  • conversation_id – present only when reconnecting to an existing conversation.

Troubleshooting

AudioWorklet InvalidStateError on first connect

Browsers freeze a freshly created AudioContext until the user interacts with the page. If your app calls connect() during component initialization, audioWorklet.addModule() pauses, the worklet never registers, and the player throws InvalidStateError: AudioWorklet does not have a valid AudioWorkletGlobalScope as soon as audio starts streaming. To avoid the race:
  • Gate the first connect() behind a user gesture (click, tap, key press)—for example, a “Start voice agent” button.
  • Await connect() inside that handler; keep any teardown logic (like disconnect()) in lifecycle cleanup.
  • Expect this to show up most during rapid local reloads or with React Strict Mode double-mounting. In real usage, the user normally clicks before the agent activates, so reconnects after the first gesture are safe.
Once the audio worklet loads successfully the first time, subsequent reconnects can happen automatically within the same session. Just ensure the initial call happens after a gesture.