f174972: Breaking: Input class removed from exports; VoiceConversation.input is now private; changeInputDevice() returns void.
The Input class is no longer exported. The input field on VoiceConversation is now private. changeInputDevice() returns Promise<void> instead of Promise<Input>.
Before:
import { Input } from "@elevenlabs/client";
const input: Input = conversation.input;
input.analyser.getByteFrequencyData(data);
input.setMuted(true);
const newInput: Input = await conversation.changeInputDevice(config);
newInput.worklet.port.postMessage(…);
After:
import type { InputController } from "@elevenlabs/client";
conversation.getInputByteFrequencyData(); // replaces input.analyser.getByteFrequencyData
conversation.setMicMuted(true); // replaces input.setMuted
await conversation.changeInputDevice(config); // return value dropped
Migration:
import { Input } with import type { InputController } if you need the type.conversation.input.analyser.getByteFrequencyData(data) with conversation.getInputByteFrequencyData().conversation.input.setMuted(v) with conversation.setMicMuted(v).changeInputDevice().f174972: Breaking: InputController and OutputController interfaces are now exported; Input and Output class exports are replaced by these interfaces.
Before:
import { Input, Output } from "@elevenlabs/client";
After:
import type { InputController, OutputController } from "@elevenlabs/client";
f174972: Breaking: Conversation is no longer a class — it is now a plain namespace object and a type alias for TextConversation | VoiceConversation.
instanceof Conversation no longer compiles. Subclassing Conversation is no longer possible. The startSession() call is unchanged.
Before:
import { Conversation } from "@elevenlabs/client";
// instanceof check compiled fine
if (session instanceof Conversation) { … }
// subclassing was possible
class MyConversation extends Conversation { … }
// startSession returned the class type
const session: Conversation = await Conversation.startSession(options);
After:
import { Conversation } from "@elevenlabs/client";
import type {
Conversation,
TextConversation,
VoiceConversation,
} from "@elevenlabs/client";
// startSession call is unchanged
const session: Conversation = await Conversation.startSession(options);
// Narrow using the concrete types or duck-typing instead of instanceof
if ("changeInputDevice" in session) {
// session is VoiceConversation
}
Migration:
instanceof Conversation checks. Narrow on TextConversation or VoiceConversation using "changeInputDevice" in session (voice) or duck-typing on the methods you need.Conversation — implement the BaseConversation interface directly or compose instead.startSession() call is unchanged and requires no migration.1dc66aa: Breaking: The default connectionType is now inferred from the conversation mode instead of always defaulting to "websocket".
"webrtc" by defaulttextOnly: true) use "websocket" by defaultUsers who previously relied on the implicit "websocket" default for voice conversations and need to keep using WebSocket must now explicitly set connectionType: "websocket".
connectionType is now optional on PublicSessionConfig (when using agentId).
f174972: Breaking: Output class removed from exports; VoiceConversation.output is now private; changeOutputDevice() returns void.
The Output class is no longer exported. The output field on VoiceConversation is now private. changeOutputDevice() returns Promise<void> instead of Promise<Output>.
Before:
import { Output } from "@elevenlabs/client";
const output: Output = conversation.output;
output.gain.gain.value = 0.5;
output.analyser.getByteFrequencyData(data);
output.worklet.port.postMessage({ type: "interrupt" });
const newOutput: Output = await conversation.changeOutputDevice(config);
After:
import type { OutputController } from "@elevenlabs/client";
conversation.setVolume({ volume: 0.5 }); // replaces output.gain.gain.value
conversation.getOutputByteFrequencyData(); // replaces output.analyser.getByteFrequencyData
// interruption is handled internally by VoiceConversation
await conversation.changeOutputDevice(config); // return value dropped
Migration:
import { Output } with import type { OutputController } if you need the type.conversation.output.gain.gain.value = v with conversation.setVolume({ volume: v }).conversation.output.analyser.getByteFrequencyData(data) with conversation.getOutputByteFrequencyData().changeOutputDevice().f174972: Breaking: VoiceConversation.wakeLock is now private.
The wakeLock field is no longer accessible on VoiceConversation. It was always an internal detail for preventing screen sleep during a session and was never intended as stable public API.
Before:
const lock: WakeLockSentinel | null = conversation.wakeLock;
if (lock) {
await lock.release();
}
After: Wake lock lifecycle is managed entirely by VoiceConversation. There is no replacement — the lock is released automatically when the session ends. If you need to suppress wake locking entirely, pass useWakeLock: false in the session options.
const conversation = await Conversation.startSession({
// …
useWakeLock: false, // opt out of wake lock management
});
getInputVolume()/getOutputVolume() and empty Uint8Array from getInputByteFrequencyData()/getOutputByteFrequencyData() instead of throwing when no active conversation or analyser is available. This avoids forcing consumers (e.g., animation loops) to wrap every call in try-catch.Fetched April 7, 2026