Expo
How do I record video with expo-camera?
Render a CameraView with mode="video", ask for camera and microphone permission, then call recordAsync() on its ref to start and stopRecording() to finish. The promise from recordAsync resolves with the video's file uri once recording stops.
Updated October 31, 2026
If you have a camera preview on screen but can’t get recordAsync to give you a video, you’re close. Video in expo-camera comes from the same CameraView component you use for photos, so what’s left is a prop that switches it into video mode, a second permission for the microphone, and knowing when the recording promise actually resolves.
How it works
CameraView shows the live preview, and the recording methods live on its ref. Calling recordAsync() starts recording and returns a promise, but that promise doesn’t resolve until recording stops, which happens when you call stopRecording(), when the video reaches a maxDuration or maxFileSize you set, or when the preview stops. It then resolves with an object holding the video’s uri, and the file is saved in your app’s cache directory.
Recording with sound needs two permissions, one for the camera and one for the microphone. Expo’s docs mark expo-camera as device only on both Android and iOS, and recordAsync isn’t available on web, so we’d test on a real phone from the start.
How to set it up
-
Install the module with
npx expo install expo-camera. -
Add the permission text to
app.jsonthrough the config plugin. The two messages are what iOS shows in its permission prompts, andrecordAudioAndroidadds Android’s record audio permission (it’s on by default). Plugin changes take effect in a new build.{ "expo": { "plugins": [ [ "expo-camera", { "cameraPermission": "Allow $(PRODUCT_NAME) to use your camera to record videos.", "microphonePermission": "Allow $(PRODUCT_NAME) to use your microphone to record sound with your videos.", "recordAudioAndroid": true } ] ] } } -
Ask for both permissions, then record. Set
mode="video", because the default mode is"picture", and wait foronCameraReadybefore you let anyone press record:import { useRef, useState } from "react"; import { Button, View } from "react-native"; import { CameraView, useCameraPermissions, useMicrophonePermissions } from "expo-camera"; export default function RecordScreen() { const camera = useRef<CameraView>(null); const [cameraPermission, requestCamera] = useCameraPermissions(); const [micPermission, requestMic] = useMicrophonePermissions(); const [ready, setReady] = useState(false); const [recording, setRecording] = useState(false); const [videoUri, setVideoUri] = useState<string | null>(null); if (!cameraPermission?.granted || !micPermission?.granted) { return ( <Button title="Allow camera and microphone" onPress={async () => { await requestCamera(); await requestMic(); }} /> ); } async function record() { setRecording(true); const video = await camera.current?.recordAsync({ maxDuration: 60 }); setRecording(false); if (video) setVideoUri(video.uri); } return ( <View style={{ flex: 1 }}> <CameraView ref={camera} style={{ flex: 1 }} mode="video" onCameraReady={() => setReady(true)} /> <Button title={recording ? "Stop" : "Record"} disabled={!ready} onPress={() => (recording ? camera.current?.stopRecording() : record())} /> </View> ); }If you don’t need sound, add the
muteprop and the video records without audio. -
Play it back with expo-video by passing the
urito a player:import { useVideoPlayer, VideoView } from "expo-video"; function Playback({ uri }: { uri: string }) { const player = useVideoPlayer(uri); return <VideoView player={player} style={{ width: "100%", height: 300 }} />; }
How you know it works
On a phone, the permission prompts show your text, the button switches between Record and Stop, and after you stop, videoUri holds a file path that plays back with sound. Because the file sits in the cache directory, which is meant for temporary files, upload it or move it somewhere permanent if you need to keep it.
If it still doesn’t record
Check that mode="video" is set and that the camera was ready before you started. Switching facing between the front and back camera during a recording stops it, which can look like recording ended on its own. Only one camera preview can be active at a time, so if another screen in your app also renders a CameraView, unmount it when that screen isn’t focused. If the video has no sound on Android, confirm recordAudioAndroid is still true and that you made a new build after changing the plugin.
Ask the agent
If your app is in Draftbit, paste this into the agent, and it can read your code and make the change for you.
Add a screen that records video with the camera. Ask for camera and microphone permission, add a button that starts and stops recording, and play the video back after it's recorded so I can check it on my phone.