Layercode agents normally consume live microphone audio, but some experiences need a text fallback—think chat bubbles, accessibility flows, or quick corrections while the mic is muted. The WebSocket API and SDKs expose sendClientResponseText for exactly that: send the full utterance as text, let the server close the user turn, and have the agent reply immediately.
This guide shows how to wire text messages in both Vanilla JS and React. If you’re working directly with the WebSocket API (for example, outside a Node environment), check the Send Text Messages (optional) reference for payload details.
Need to push structured data (form values, button clicks) without ending the turn? See Send JSON data from the client.
Starting in text-only mode? Pass audioInput: false (and optionally enableAmplitudeMonitoring: false) when you instantiate the SDK. The browser skips the microphone permission prompt until you later call setAudioInput(true).
1) Vanilla JS example
The LayercodeClient instance exposes sendClientResponseText. Add a simple form that forwards the entered text and clears the field when submitted.
<form id="text-response-form">
<input
id="client-response-text"
type="text"
placeholder="Type your reply"
/>
<button type="submit">Send</button>
</form>
<script type="module">
import LayercodeClient from 'https://cdn.jsdelivr.net/npm/@layercode/js-sdk@latest/dist/layercode-js-sdk.esm.js';
window.layercode = new LayercodeClient({
agentId: 'your-agent-id',
authorizeSessionEndpoint: '/api/authorize'
});
window.layercode.connect();
const form = document.getElementById('text-response-form');
const input = document.getElementById('client-response-text');
form.addEventListener('submit', (event) => {
event.preventDefault();
const message = input.value.trim();
if (!message) return;
window.layercode.sendClientResponseText(message);
input.value = '';
});
</script>
What happens when you call sendClientResponseText:
- The client sends a
client.response.text message (no trigger.turn.end is sent from the SDK).
- The server interrupts any active agent audio, emits a
user.transcript event, closes the current user turn, and queues the agent response.
- The agent receives the text message through the regular webhook path and responds immediately.
2) React example
The React SDK exposes the same capability via the useLayercodeAgent hook. Grab the sendClientResponseText method from the hook and call it from your form handler.
app/components/TextReplyForm.tsx
'use client';
import { FormEvent, useEffect } from 'react';
import { useLayercodeAgent } from '@layercode/react-sdk';
export function TextReplyForm() {
const { status, connect, disconnect, sendClientResponseText } = useLayercodeAgent({
agentId: process.env.NEXT_PUBLIC_LAYERCODE_AGENT_ID!,
authorizeSessionEndpoint: '/api/authorize',
});
useEffect(() => {
connect();
return () => {
disconnect();
};
}, [connect, disconnect]);
const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
const form = event.currentTarget;
const data = new FormData(form);
const message = (data.get('message') as string).trim();
if (!message) return;
sendClientResponseText(message);
form.reset();
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
name="message"
placeholder="Type a reply"
disabled={status !== 'connected'}
/>
<button type="submit" disabled={status !== 'connected'}>
Send
</button>
</form>
);
}
Disable the form while the client is still connecting so you do not cue messages before a session exists.
When you want to escalate from text to voice mode, grab setAudioInput from the hook:const { setAudioInput } = useLayercodeAgent({
audioInput: false,
enableAmplitudeMonitoring: false,
// ...other options
});
return <button onClick={() => setAudioInput(true)}>Enable voice</button>;