By default, the hosted chat widget’s attach button uses the WebView file input. On low-RAM Android devices this can be unreliable because the system camera can kill the WebView render process while capture is in progress.
Configure filePicker so the attach button uses native pickers instead. Picked files are delivered to the hosted widget over the SDK bridge, mirrored to cache when configured, and re-delivered until the widget acknowledges them.
Choose a picker path
Use one of these approaches:
- Install
@sagepilot-ai/react-native-camera-addon for Sagepilot’s Android in-app CameraX picker.
- Use
createSagepilotFilePicker(...) from the base SDK when your app already provides camera, gallery, or document picker modules.
The base chat SDK does not bundle CameraX or CameraX Gradle dependencies.
Android CameraX addon
Install the addon when your Android app wants Sagepilot’s in-app CameraX picker:
npm install @sagepilot-ai/react-native-camera-addon@latest
The addon adds these Android dependencies through its own Gradle file:
| Dependency | Purpose |
|---|
androidx.camera:camera-core | CameraX core APIs |
androidx.camera:camera-camera2 | Camera2 implementation |
androidx.camera:camera-lifecycle | Lifecycle-aware camera binding |
androidx.camera:camera-view | Camera preview UI |
androidx.exifinterface:exifinterface | Image metadata handling |
androidx.activity:activity | Activity result and AndroidX activity support |
By default, the addon uses CameraX 1.5.3, ExifInterface 1.4.2, and AndroidX Activity 1.10.1. Override them from the root Gradle project with sagepilotCameraXVersion, sagepilotExifInterfaceVersion, and sagepilotActivityVersion when your app needs pinned AndroidX versions.
Run a fresh native Android build after installing the addon. A Metro reload is not enough for React Native autolinking to register NativeModules.SagepilotInAppCamera.
For Expo apps, use a native/dev-client build:
For bare React Native apps, clean and rebuild Android:
cd android && ./gradlew clean
cd ..
npx react-native run-android
Request and confirm Android CAMERA permission before users open the Sagepilot CameraX picker. Do not rely on the first camera tap inside the widget to show the runtime permission prompt. On some Android devices, that first permission flow can pause the app and cause the hosted WebView to reload.
Then pass the addon picker to configure():
import { SagepilotChat } from "@sagepilot-ai/react-native-sdk";
import { createSagepilotCameraXFilePicker } from "@sagepilot-ai/react-native-camera-addon";
await SagepilotChat.configure({
key: "workspace_id:channel_id",
filePicker: createSagepilotCameraXFilePicker({
includeCamera: true,
includeLibrary: true,
includeDocuments: true
})
});
createSagepilotCameraXFilePicker() returns undefined outside Android, so shared app setup can call it safely. On iOS, no additional setup is required for the CameraX addon unless your app provides its own native iOS picker.
With this adapter enabled on Android, the hosted widget routes each attachment action to its matching native source:
| Attachment action | Native source |
|---|
| Camera | In-app CameraX capture |
| Gallery | Android media/photo picker |
| Files | Android document picker |
When the addon advertises these sources, gallery and file actions do not use a generic WebView file chooser.
Host-provided picker modules
Use this path when your app already owns picker dependencies or needs a custom iOS picker.
Install only the modules your app needs:
# Camera and photo gallery
npm install react-native-image-picker
# Document/file picking
npm install @react-native-documents/picker
# Reliable document reads and durable file storage
npm install react-native-blob-util
# Durable picked-file batch manifests
npm install @react-native-async-storage/async-storage
Then pass those modules to createSagepilotFilePicker(...):
import AsyncStorage from "@react-native-async-storage/async-storage";
import * as imagePicker from "react-native-image-picker";
import * as documentsPicker from "@react-native-documents/picker";
import ReactNativeBlobUtil from "react-native-blob-util";
import {
SagepilotChat,
createAsyncStorageCacheStorage,
createSagepilotFilePicker,
createSagepilotFileStore
} from "@sagepilot-ai/react-native-sdk";
await SagepilotChat.configure({
key: "workspace_id:channel_id",
cacheStorage: createAsyncStorageCacheStorage(AsyncStorage),
fileStore: createSagepilotFileStore(ReactNativeBlobUtil),
filePicker: createSagepilotFilePicker({
imagePicker,
documentsPicker,
fileReader: ReactNativeBlobUtil
})
});
The base SDK uses only the picker modules you pass into createSagepilotFilePicker(...).
Durable recovery
For the strongest recovery path, pass both cacheStorage and fileStore.
cacheStorage stores the picked-file batch manifest. fileStore stores picked-file bytes in app-private storage so a captured photo or document can survive an app-process restart within the hosted widget’s upload limits.
Upload limits
The hosted widget enforces the final attachment limits for both WebView and native picker flows.
| Limit | Value |
|---|
| Files per send | Up to 5 files |
| Previewable images | Up to 5 MB total |
| Non-image files | Up to 10 MB total |
The native picker also applies earlier safety guards before files are read into memory.
| Guard | Default |
|---|
| Gallery multi-select | 5 files |
| Documents | Reject above 20 MB |
| Images | Reject above 15 MB |
These picker guards reduce out-of-memory risk. They do not raise the hosted widget’s final upload limits.
- The CameraX addon is Android-only. It owns CameraX dependencies, the native module, camera activity, overlay, and image processing.
- Camera and gallery images are downscaled natively to keep memory and upload sizes low.
- Picker failures are surfaced with typed error codes such as
permission_denied, camera_unavailable, encode_failed, file_too_large, and read_failed.
- Android apps that use the CameraX addon must grant
CAMERA at runtime before opening the Sagepilot picker. If permission is missing or denied, ask users to grant it from your app flow or Android settings before presenting the camera action again.
- No additional iOS setup is required for the CameraX addon. Add iOS permission strings only if your app separately provides its own native iOS picker.
- Apps that skip
filePicker keep the WebView file input. The SDK can recover from WebView renderer crashes, but a photo captured at crash time cannot be restored in that mode.