This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.

Expo Audio (expo-audio) iconExpo Audio (expo-audio)

A library that provides an API to implement audio playback and recording in apps.

Android
iOS
tvOS
Web
Included in Expo Go
Recommended version:
~56.0.13

expo-audio is a cross-platform audio library for accessing the native audio capabilities of the device.

The Android media format support documentation covers formats supported when using Expo Player on Android. The iOS audio and video format documentation lists supported media formats for Apple devices.

Note that audio automatically stops if headphones/Bluetooth audio devices are disconnected.

Installation

Terminal
- npx expo install expo-audio
- yarn expo install expo-audio
- pnpm expo install expo-audio
- bun expo install expo-audio

If you are installing this in an existing React Native app, make sure to install expo in your project.

Configuration in app config

You can configure expo-audio using its built-in config plugin if you use config plugins in your project (Continuous Native Generation (CNG)). The plugin allows you to configure various properties that cannot be set at runtime and require building a new app binary to take effect. If your app does not use CNG, then you'll need to manually configure the library.

Example app.json with config plugin

app.json
{ "expo": { "plugins": [ [ "expo-audio", { "microphonePermission": "Allow $(PRODUCT_NAME) to access your microphone.", "enableBackgroundPlayback": true, "enableBackgroundRecording": false } ] ] } }

Configurable properties

NameDefaultDescription
microphonePermission"Allow $(PRODUCT_NAME) to access your microphone"
Only for: 
iOS

A string to set the NSMicrophoneUsageDescription permission message. Setting it to false will disable the permission.

recordAudioAndroidtrue
Only for: 
Android

A boolean that determines whether to enable the RECORD_AUDIO permission on Android.

enableBackgroundRecordingfalse

A boolean that determines whether to enable background audio recording. On Android, this adds a recording foreground service and permissions and displays a persistent notification during recording. On iOS, this adds the audio background mode. Note: Background recording can significantly impact battery life.

enableBackgroundPlaybacktrue

A boolean that determines whether to enable background audio playback. On Android, this adds a media playback foreground service and allows you to display the lockscreen controls and is required for sustained background playback. On iOS, this adds the audio background mode.

Usage

Playing sounds

Playing sounds
import { View, StyleSheet, Button } from 'react-native'; import { useAudioPlayer } from 'expo-audio'; const audioSource = require('./assets/Hello.mp3'); export default function App() { const player = useAudioPlayer(audioSource); return ( <View style={styles.container}> <Button title="Play Sound" onPress={() => player.play()} /> <Button title="Replay Sound" onPress={() => { player.seekTo(0); player.play(); }} /> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', backgroundColor: '#ecf0f1', padding: 10, }, });

Recording sounds

Recording sounds
import { useState, useEffect } from 'react'; import { View, StyleSheet, Button } from 'react-native'; import { useAudioRecorder, AudioModule, RecordingPresets, setAudioModeAsync, useAudioRecorderState, } from 'expo-audio'; export default function App() { const audioRecorder = useAudioRecorder(RecordingPresets.HIGH_QUALITY); const recorderState = useAudioRecorderState(audioRecorder); const record = async () => { await audioRecorder.prepareToRecordAsync(); audioRecorder.record(); }; const stopRecording = async () => { // The recording will be available on `audioRecorder.uri`. await audioRecorder.stop(); }; useEffect(() => { (async () => { const status = await AudioModule.requestRecordingPermissionsAsync(); if (!status.granted) { Alert.alert('Permission to access microphone was denied'); } setAudioModeAsync({ playsInSilentMode: true, allowsRecording: true, }); })(); }, []); return ( <View style={styles.container}> <Button title={recorderState.isRecording ? 'Stop Recording' : 'Start Recording'} onPress={recorderState.isRecording ? stopRecording : record} /> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', backgroundColor: '#ecf0f1', padding: 10, }, });

On Android and iOS, expo-audio saves recordings in the app's cache directory by default. The system may delete cache files when the device runs low on storage. To keep new recordings in a more persistent location, pass { ...RecordingPresets.HIGH_QUALITY, directory: 'document' } to useAudioRecorder or prepareToRecordAsync(). This stores them under the app's document directory. For existing recordings already saved in cache, use the returned recording URI to move them with expo-file-system.

Playing audio in the background

Background audio playback allows your app to continue playing audio when it moves to the background or when the device screen locks.

Configuration

To enable background audio playback, use the config plugin in your app config:

app.json
{ "expo": { "plugins": [ [ "expo-audio", { "enableBackgroundPlayback": true } ] ] } }

The above configuration automatically configures the required native settings:

  • Android
    Adds FOREGROUND_SERVICE and FOREGROUND_SERVICE_MEDIA_PLAYBACK permissions. Also declares a media playback foreground service (AudioControlsService) in app's AndroidManifest.xml.
  • iOS
    Adds the audio UIBackgroundMode capability

Usage

After configuring your app with the config plugin, you need to:

  1. Configure the audio session to allow background playback
  2. Enable lock screen controls (required on Android for sustained background playback)
import { View, Button } from 'react-native'; import { useAudioPlayer, setAudioModeAsync } from 'expo-audio'; import { useEffect } from 'react'; export default function AudioPlayerScreen() { const audioSource = require('./assets/audio.mp3'); const player = useAudioPlayer(audioSource); useEffect(() => { // Configure audio session for background playback setAudioModeAsync({ playsInSilentMode: true, shouldPlayInBackground: true, interruptionMode: 'doNotMix', }); }, []); const handlePlay = () => { // Enable lock screen controls with metadata player.setActiveForLockScreen(true, { title: 'My Audio Title', artist: 'Artist Name', albumTitle: 'Album Name', artworkUrl: 'https://example.com/artwork.jpg', // optional }); // Start playback - this will continue in the background player.play(); }; const handleStop = () => { player.pause(); // Optionally disable lock screen controls when done player.setActiveForLockScreen(false); }; return ( <View> <Button title="Play" onPress={handlePlay} /> <Button title="Stop" onPress={handleStop} /> </View> ); }
Android
  • A media notification appears in the notification drawer with playback controls
  • Audio continues playing indefinitely in the background
  • Users can control playback from the lock screen and notification
  • The foreground service keeps the playback alive during playback
iOS

On iOS, audio playback continues seamlessly in the background once the audio session is configured with shouldPlayInBackground: true. Lock screen controls are optional but enhance the user experience by providing playback controls on the lock screen and Control Center.

Are you using this library in an existing React Native app?

If you're not using Continuous Native Generation (CNG) (you're using native android and ios projects manually), then you need to configure the following for background playback:

  • For Android, add to android/app/src/main/AndroidManifest.xml:

    android/app/src/main/AndroidManifest.xml
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" /> <application> <!-- Other application components --> <service android:name="expo.modules.audio.service.AudioControlsService" android:exported="false" android:foregroundServiceType="mediaPlayback"> <intent-filter> <action android:name="androidx.media3.session.MediaSessionService" /> </intent-filter> </service> </application>
  • For iOS, add to ios/YourApp/Info.plist:

    ios/YourApp/Info.plist
    <key>UIBackgroundModes</key> <array> <string>audio</string> </array>

Recording audio in the background

Background audio recording allows your app to continue recording when it moves to the background or when the device screen locks.

To enable background recording, use the config plugin in your app config:

app.json
{ "expo": { "plugins": [ [ "expo-audio", { "microphonePermission": "Allow $(PRODUCT_NAME) to record audio.", "enableBackgroundRecording": true } ] ] } }

The above configuration automatically configures the required native settings:

  • Android
    Adds FOREGROUND_SERVICE, FOREGROUND_SERVICE_MICROPHONE, and POST_NOTIFICATIONS permissions. Also declares an audio recording foreground service in app's AndroidManifest.xml.
  • iOS
    Adds the audio UIBackgroundMode capability
Are you using this library in an existing React Native app?

If you're not using Continuous Native Generation (CNG) (you're using native android and ios projects manually), then you need to configure the following permissions in your native projects:

  • For Android, add to android/app/src/main/AndroidManifest.xml:

    android/app/src/main/AndroidManifest.xml
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
  • For iOS, add to ios/YourApp/Info.plist:

    ios/YourApp/Info.plist
    <key>UIBackgroundModes</key> <array> <string>audio</string> </array>

Usage

After configuring your app, enable background recording at runtime using setAudioModeAsync:

import { setAudioModeAsync, useAudioRecorder, RecordingPresets } from 'expo-audio'; await setAudioModeAsync({ playsInSilentMode: true, allowsRecording: true, allowsBackgroundRecording: true, }); const recorder = useAudioRecorder(RecordingPresets.HIGH_QUALITY); await recorder.prepareToRecordAsync(); await recorder.record(); // Recording continues in background
Android

On Android, background recording requires a foreground service, which displays a persistent notification with the text "Recording audio" and a stop button. This notification cannot be dismissed while recording is active and automatically disappears when recording stops.

iOS

On iOS, background recording continues seamlessly when the app is in the background or the screen locks. No additional notifications or indicators are shown to the app user beyond the system status bar.

Using the AudioPlayer directly

In most cases, use the useAudioPlayer hook to create an AudioPlayer instance. It manages the player's lifecycle and ensures proper disposal when the component unmounts. However, in some advanced use cases, you may need to create an AudioPlayer that persists beyond the component's lifecycle. In those cases, use the createAudioPlayer function. You need to be aware of the risks that come with this approach, as it is your responsibility to call the release() method when the player is no longer needed. If not handled properly, this approach may lead to memory leaks.

import { createAudioPlayer } from 'expo-audio'; const player = createAudioPlayer(audioSource);

Notes on web usage

  • A MediaRecorder issue on Chrome produces WebM files missing the duration metadata. See the open Chromium issue.
  • MediaRecorder encoding options and other configurations are inconsistent across browsers. Using a polyfill such as kbumsik/opus-media-recorder or ai/audio-recorder-polyfill in your application will improve your experience. Any options passed to prepareToRecordAsync will be passed directly to the MediaRecorder API and as such the polyfill.
  • Web browsers require sites to be served securely for them to listen to a mic. See MediaDevices getUserMedia() security for more details.

API

import { useAudioPlayer, useAudioRecorder } from 'expo-audio';

No API data file found, sorry!