This is beta documentation for Stream Chat React SDK v14. For the latest stable version, see the latest version (v13) .

Audio Recorder

Enable audio recording on MessageInput to let users record voice messages.

import { MessageInput } from "stream-chat-react";

const Composer = () => <MessageInput audioRecordingEnabled />;

Once enabled, the composer renders StartRecordingAudioButton. When recording starts, MessageInputFlat swaps the normal composer UI for AudioRecorder.

Best Practices

  • Enable recording only where voice messages make sense for the product.
  • Use asyncMessagesMultiSendEnabled if users should be able to combine text, attachments, and voice recordings before sending.
  • Customize recording UI through WithComponents, not dead Channel override 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:

  • StartRecordingAudioButton
  • AudioRecorder
  • RecordingPermissionDeniedNotification

Use WithComponents to override them:

import { Channel, MessageInput, 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>
      <MessageInput 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:

PropType
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:

  1. Install @breezystack/lamejs.
npm install @breezystack/lamejs
yarn add @breezystack/lamejs
  1. Pass the encoder through audioRecordingConfig.
import { useMemo } from "react";
import { MessageInput } from "stream-chat-react";
import { encodeToMp3 } from "stream-chat-react/mp3-encoder";

const Composer = () => {
  const audioRecordingConfig = useMemo(
    () => ({ transcoderConfig: { encoder: encodeToMp3 } }),
    [],
  );

  return (
    <MessageInput
      audioRecordingConfig={audioRecordingConfig}
      audioRecordingEnabled
    />
  );
};

Sending Behavior

The recording uploads when recording is completed.

Sending behavior is controlled by asyncMessagesMultiSendEnabled on MessageInput:

asyncMessagesMultiSendEnabledBehavior
falseuploads and sends the voice recording immediately
truekeeps 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 MessageInputContext can read recorder state through recordingController:

import { useMessageInputContext } from "stream-chat-react";

const RecorderStatus = () => {
  const {
    recordingController: {
      completeRecording,
      permissionState,
      recorder,
      recording,
      recordingState,
    },
  } = useMessageInputContext();

  return (
    <pre>
      {JSON.stringify(
        {
          hasRecorder: !!recorder,
          permissionState,
          recordingState,
          hasRecording: !!recording,
        },
        null,
        2,
      )}
    </pre>
  );
};

The controller exposes:

PropertyDescription
completeRecordingstops recording and finalizes the voice attachment
permissionStatecurrent browser permission state
recordermedia-recorder controller instance
recordinggenerated voice-recording attachment after stop
recordingStatecurrent recording lifecycle state