Installation
Install the SDK in a few steps:
Best Practices
- Choose RN CLI vs Expo tabs based on your app runtime; don't mix dependencies across runtimes.
- Install only the optional features you need to keep bundle size and native setup lean.
- Add required platform permissions as you enable features (audio, camera, media library).
- Follow each dependency’s post-install steps to avoid runtime errors.
- Keep Reanimated/Worklets Babel plugin last and wrap the app in
GestureHandlerRootView.
Prerequisites
Set up the React Native development environment: React Native guide.
For Expo, follow this guide.
Add Stream Chat SDK and peer dependencies
Install the SDK:
yarn add stream-chat-react-nativenpx expo install stream-chat-expoInstall peer dependencies:
yarn add @react-native-community/netinfo react-native-gesture-handler react-native-reanimated react-native-teleport react-native-worklets react-native-svg react-native-safe-area-contextnpx expo install @react-native-community/netinfo expo-image-manipulator react-native-gesture-handler react-native-reanimated react-native-svg react-native-teleport react-native-safe-area-contextInstalled packages:
@react-native-community/netinfofor network state.react-native-gesture-handlerfor gestures.react-native-reanimatedfor animations.react-native-teleportfor the portal-based overlay system.react-native-workletsrequired byreact-native-reanimated.react-native-svgfor SVG support.react-native-safe-area-contextfor safe-area insets.
@react-native-community/netinfofor network state.react-native-gesture-handlerfor gestures.expo-image-manipulatorto compress images.react-native-reanimatedfor animations.react-native-teleportfor the portal-based overlay system.react-native-svgfor SVG support.react-native-safe-area-contextfor safe-area insets.
react-native-teleport is required in V9 because OverlayProvider uses it for message overlays and portal-hosted UI.
If you use Expo prebuild or native builds, run npx expo prebuild after adding react-native-teleport or other native packages with config plugins.
If You Use React Navigation
The navigation examples in these docs also use react-native-safe-area-context for SafeAreaProvider and useSafeAreaInsets. It is a required Stream peer dependency and is already installed in the peer-dependency step above, so no extra install is needed. If you skipped that step, install it with:
yarn add react-native-safe-area-contextnpx expo install react-native-safe-area-contextOpt-in features
Optional features require additional dependencies.
Video playing
yarn add react-native-videonpx expo install expo-videoVoice recording and audio attachments
yarn add react-native-audio-recorder-player react-native-blob-utilFor Expo, both expo-av and expo-audio are supported.
npx expo install expo-avnpx expo install expo-audioexpo-audio is supported from version 7.2.0 of stream-chat-expo.
Even though both libraries are supported and adapted to a singular API, different supported Expo versions do not work interoperably with each of the libraries.
More specifically, if you're using Expo 51.x.x or 52.x.x please make sure to keep using expo-av as expo-audio is unstable and will likely not work properly in those versions.
Conversely, if you're using Expo >=53.0.0, please make sure to use expo-audio as support for expo-av has stopped completely in favor of the new library. While it is already not supported, Expo 54 is not going to contain expo-av at all in Expo Go, meaning the sooner you get to go to Expo 53 and use the new library, the better.
Configuring permissions
react-native-audio-recorder-playerfor microphone access for voice recording.
An example AndroidManifest.xml would look like this with permissions:
<uses-permission android:name="android.permission.RECORD_AUDIO" />An example Info.plist would look like this with permissions:
<key>NSMicrophoneUsageDescription</key>
<string>$(PRODUCT_NAME) would like to use your microphone for voice recording.</string>Setup varies slightly for each option:
expo-avfor microphone access for voice recording.
An example app.json config for expo would look like this to add permissions to the Info.plist on iOS, using the config plugins:
expo-audiofor microphone access for voice recording.
An example app.json config for expo would look like this to add permissions to the Info.plist on iOS, using the config plugins:
{
"expo": {
"plugins": [
// ... rest of the plugins
[
"expo-audio",
{
"microphonePermission": "$(PRODUCT_NAME) would like to use your microphone for voice recording."
}
]
]
}
}On Android (Expo), most permissions are added automatically by libraries via config plugins or package-level AndroidManifest.xml. Read more here.
expo-videofor video related configuration.
An example app.json config for expo would look like this:
{
"expo": {
"plugins": [
// ... rest of the plugins
[
"expo-video",
{
"supportsBackgroundPlayback": true,
"supportsPictureInPicture": true
}
]
]
}
}Attachment sharing
Share attachments outside the app.
yarn add react-native-blob-util react-native-sharenpx expo install expo-sharingHaptic feedback
Provide haptic feedback to the user.
yarn add react-native-haptic-feedbacknpx expo install expo-hapticsCopy message
Copy the text message content to the clipboard.
yarn add @react-native-clipboard/clipboardnpx expo install expo-clipboardShare file attachments
Share files from the device.
yarn add @react-native-documents/pickernpx expo install expo-document-pickerCapture image and upload attachment
Capture images from the camera and upload them.
yarn add react-native-image-pickernpx expo install expo-image-pickerConfiguring permissions
react-native-image-pickerfor camera access.
On Android, an example AndroidManifest.xml would look like this with permissions:
<uses-permission android:name="android.permission.CAMERA" />On iOS, an example Info.plist would look like this with permissions:
<key>NSCameraUsageDescription</key>
<string>$(PRODUCT_NAME) would like to use your camera to share image in a message.</string>expo-image-pickerfor camera access.
An example app.json config for expo would look like this to add permissions to the Info.plist on iOS, using the config plugins:
{
"expo": {
"plugins": [
[
"expo-image-picker",
{
"cameraPermission": "$(PRODUCT_NAME) would like to use your camera to share image in a message."
}
]
]
}
}Pick image using Native Image Picker
Pick gallery images using the native picker and upload them.
yarn add react-native-image-pickernpx expo install expo-image-pickerConfiguring permissions
react-native-image-pickerfor photo library access.
On Android, no permissions are required.
On iOS, an example Info.plist would look like this with permissions:
<key>NSPhotoLibraryUsageDescription</key>
<string>$(PRODUCT_NAME) would like access to your photo gallery to share image in a message.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>$(PRODUCT_NAME) would like to save photos to your photo gallery after downloading from a message.</string>expo-image-pickerfor camera access.
An example app.json config for expo would look like this to add permissions to the Info.plist on iOS, using the config plugins:
{
"expo": {
"plugins": [
[
"expo-image-picker",
{
"photosPermission": "$(PRODUCT_NAME) would like to use your device gallery to attach image in a message."
}
]
]
}
}Built-in image media library
Pick images using the built-in media library and upload them.
yarn add @react-native-camera-roll/camera-rollnpx expo install expo-media-libraryConfiguring permissions
@react-native-camera-roll/camera-rollfor gallery/photo library access.
An example AndroidManifest.xml would look like this with permissions:
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />An example Info.plist would look like this with permissions:
<key>NSPhotoLibraryUsageDescription</key>
<string>$(PRODUCT_NAME) would like access to your photo gallery to share image in a message.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>$(PRODUCT_NAME) would like to save photos to your photo gallery after downloading from a message.</string>expo-media-libraryfor gallery/photo library access.
An example app.json config for expo would look like this to add permissions to the Info.plist on iOS, using the config plugins:
{
"expo": {
"plugins": [
[
"expo-media-library",
{
"photosPermission": "$(PRODUCT_NAME) would like access to your photo gallery to share image in a message.",
"savePhotosPermission": "$(PRODUCT_NAME) would like to save photos to your photo gallery after downloading from a message."
}
]
]
}
}On Android (Expo), most permissions are added automatically by libraries via config plugins or package-level AndroidManifest.xml. Read more here.
Offline support
Enable offline support.
yarn add @op-engineering/op-sqlitenpx expo install @op-engineering/op-sqliteHigh-performance message list
For better performance with large message lists, you can use @shopify/flash-list instead of the default FlatList. This is especially useful for channels with thousands of messages.
yarn add @shopify/flash-listnpx expo install @shopify/flash-listSee the FlashList documentation for more information on using FlashList with the SDK.
The overall installation of the optional dependencies would look like this:
@react-native-camera-roll/camera-rollfor gallery access.react-native-videofor video/audio playback.react-native-audio-recorder-playerfor audio recording.react-native-blob-utilfor file operations and cache access.react-native-sharefor sharing.react-native-haptic-feedbackfor haptics.@react-native-clipboard/clipboardfor clipboard.@react-native-documents/pickerfor file picking (required overreact-native-document-pickeron React Native>=0.78.0).react-native-image-pickerfor camera/gallery picking.@op-engineering/op-sqlitefor offline storage.
expo-avfor audio playback/recording.expo-videofor video playback/preview.expo-file-systemfor file operations and cache access.expo-media-libraryfor gallery access.expo-sharingfor sharing.expo-hapticsfor haptics.expo-clipboardfor clipboard.expo-document-pickerfor file picking.expo-image-pickerfor camera/gallery picking.@op-engineering/op-sqlitefor offline storage.
Follow each dependency's setup instructions to ensure proper integration.
Additional Steps
Some dependencies require extra app configuration:
- Add the Babel plugin for
react-native-reanimatedinbabel.config.js:
module.exports = {
presets: [
... // don't add it here :)
],
plugins: [
...
'react-native-reanimated/plugin',
],
};react-native-reanimated/plugin has to be listed last.
If you are using react-native-reanimated version >=4.0.0, you can replace the react-native-reanimated/plugin with react-native-worklets/plugin in your application's babel.config.js.
module.exports = {
presets: [
... // don't add it here :)
],
plugins: [
...
'react-native-worklets/plugin',
],
};Read more here.
- After installation, wrap your entry point with
<GestureHandlerRootView>orgestureHandlerRootHOC:
import { GestureHandlerRootView } from "react-native-gesture-handler";
export default function App() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
{/* content */}
</GestureHandlerRootView>
);
}Your entry point is usually index.js or App.tsx. For Expo Router v3.x, use app/_layout.js.
Please also follow the steps mentioned in the links below for corresponding dependencies:
react-native- additional installation steps
Run the app:
npx pod-install
yarn iosyarn androidyarn run iosyarn run android