Audio Recorder
Enable audio recording on MessageComposer to let users record voice messages.
import { MessageComposer } from "stream-chat-react";
const Composer = () => <MessageComposer audioRecordingEnabled />;Once enabled, the composer renders StartRecordingAudioButton. When recording starts, MessageComposerUI swaps the normal composer UI for AudioRecorder.
Best Practices
- Enable recording only where voice messages make sense for the product.
- Use
asyncMessagesMultiSendEnabledif users should be able to combine text, attachments, and voice recordings before sending. - Customize recording UI through
WithComponents, not deadChanneloverride props. - Keep permission-denied messaging short and actionable.
- Test both immediate-send and stacked-send behavior when changing recording flows.
UI Customization
The default recording surfaces are provided through ComponentContext:
StartRecordingAudioButtonAudioRecorderRecordingPermissionDeniedNotification
Use WithComponents to override them:
import { Channel, MessageComposer, WithComponents } from "stream-chat-react";
const CustomStartRecordingAudioButton = (props) => (
<button {...props}>Record</button>
);
const CustomAudioRecorder = () => <div>Custom recorder UI</div>;
const CustomRecordingPermissionDeniedNotification = () => (
<div>Allow microphone access in your browser settings.</div>
);
const App = () => (
<WithComponents
overrides={{
AudioRecorder: CustomAudioRecorder,
RecordingPermissionDeniedNotification:
CustomRecordingPermissionDeniedNotification,
StartRecordingAudioButton: CustomStartRecordingAudioButton,
}}
>
<Channel>
<MessageComposer audioRecordingEnabled />
</Channel>
</WithComponents>
);The custom components above are app-owned examples.
Browser Permissions
If microphone permission is denied when the user tries to start recording, the SDK opens a callout anchored to the recording button and renders RecordingPermissionDeniedNotification.
The default notification component receives only:
| Prop | Type |
|---|---|
permissionName |
"microphone" | "camera" |
The close behavior is managed by the SDK dialog layer. Custom notification components do not receive an onClose callback.
Custom Encoding
By default, recordings are encoded as audio/wav. To reduce size, you can use the MP3 encoder plugin based on lamejs:
- Install
@breezystack/lamejs.
npm install @breezystack/lamejsyarn add @breezystack/lamejs- Pass the encoder through
audioRecordingConfig.
import { useMemo } from "react";
import { MessageComposer } from "stream-chat-react";
import { encodeToMp3 } from "stream-chat-react/mp3-encoder";
const Composer = () => {
const audioRecordingConfig = useMemo(
() => ({ transcoderConfig: { encoder: encodeToMp3 } }),
[],
);
return (
<MessageComposer
audioRecordingConfig={audioRecordingConfig}
audioRecordingEnabled
/>
);
};Sending Behavior
The recording uploads when recording is completed.
Sending behavior is controlled by asyncMessagesMultiSendEnabled on MessageComposer:
asyncMessagesMultiSendEnabled |
Behavior |
|---|---|
false |
uploads and sends the voice recording immediately |
true |
keeps the voice recording in the composer preview stack until the user submits the whole composition |
When a recording stays in the composer, it is rendered in the dedicated VoiceRecordingPreviewSlot.
Recording Controller
Components consuming MessageComposerContext can read recorder state through recordingController:
import { useMessageComposerContext } from "stream-chat-react";
const RecorderStatus = () => {
const {
recordingController: {
completeRecording,
permissionState,
recorder,
recording,
recordingState,
},
} = useMessageComposerContext();
return (
<pre>
{JSON.stringify(
{
hasRecorder: !!recorder,
permissionState,
recordingState,
hasRecording: !!recording,
},
null,
2,
)}
</pre>
);
};The controller exposes:
| Property | Description |
|---|---|
completeRecording |
stops recording and finalizes the voice attachment |
permissionState |
current browser permission state |
recorder |
media-recorder controller instance |
recording |
generated voice-recording attachment after stop |
recordingState |
current recording lifecycle state |