Getting Started
Copy a setup prompt with the install steps and the full markdown guide for this plugin.
Set up this Capacitor plugin in the project.
Use the package manager already used by the project.
Install these package(s): `@capgo/capacitor-audio-recorder`
Run the required Capacitor sync/update step after installation.
Read this markdown guide for the full setup steps: https://raw.githubusercontent.com/Cap-go/website/refs/heads/main/apps/docs/src/content/docs/docs/plugins/audio-recorder/getting-started.mdx
Use that guide for platform-specific steps, native file edits, permissions, config changes, imports, and usage setup.
If that guide references other docs pages, read them too.
Install
Section titled “Install”You can use our AI-Assisted Setup to install the plugin. Add the Capgo skills to your AI tool using the following command:
npx skills add https://github.com/Cap-go/capgo-skills --skill capacitor-pluginsThen use the following prompt:
Use the `capacitor-plugins` skill from `Cap-go/capgo-skills` to install the `@capgo/capacitor-audio-recorder` plugin in my project.If you prefer Manual Setup, install the plugin by running the following commands and follow the platform-specific instructions below:
bun add @capgo/capacitor-audio-recorderbunx cap syncImport
Section titled “Import”import { CapacitorAudioRecorder } from '@capgo/capacitor-audio-recorder';Quick start
Section titled “Quick start”Request the microphone, record, then stop and read the native file URI (or web Blob).
import { Capacitor } from '@capacitor/core';import { CapacitorAudioRecorder } from '@capgo/capacitor-audio-recorder';
const mic = await CapacitorAudioRecorder.requestPermissions();if (mic.recordAudio !== 'granted') { throw new Error('Microphone permission required');}
await CapacitorAudioRecorder.startRecording({ sampleRate: 44100, bitRate: 128000, resetToPlaybackOnStop: true, // iOS only: restore playback-friendly audio session after stop});
const { uri, blob, duration } = await CapacitorAudioRecorder.stopRecording();const clipRef = Capacitor.getPlatform() === 'web' ? blob : uri;console.log('Saved clip', clipRef, duration);Crash-safe recording (format: 'aac')
Section titled “Crash-safe recording (format: 'aac')”Requires @capgo/capacitor-audio-recorder 8.4.0 or newer from capacitor-audio-recorder PR #35. Merge and release that plugin change before relying on this API in production.
When to use it
Section titled “When to use it”Use format: 'aac' for irreplaceable audio: interviews, compliance notes, medical or legal memos, and any clip where losing the whole file is worse than losing the tail after an abnormal end.
Keep the default format: 'm4a' when you control the lifecycle (short clips, always in foreground, you can tolerate losing a take on crash) or when downstream tools expect .m4a and never .aac.
How it works
Section titled “How it works”format | Container | After an abnormal end (crash, kill, dead battery) |
|---|---|---|
'm4a' (default) | MPEG-4 AAC in .m4a | Often unreadable until moov is written at stop() |
'aac' | ADTS AAC in .aac | Readable up to the last complete frame |
Encoding settings are the same AAC bit rate and sample rate you already pass to startRecording. Web ignores format and keeps using the browser MediaRecorder.
await CapacitorAudioRecorder.startRecording({ format: 'aac', sampleRate: 44100, bitRate: 128000,});Tradeoffs
Section titled “Tradeoffs”- Playback and sharing:
.aac(ADTS) is widely supported on mobile but some desktop pipelines expect.m4a. Convert in your backend if reviewers require MPEG-4. - File size and seeking: ADTS has no index like MPEG-4. Seeking and duration metadata can be less precise until the file is fully finalized.
- iOS interruptions: Phone calls and audio session handoffs can leave multiple segment files. On stop, the plugin joins ADTS segments without re-encoding when possible.
Platform notes for stopRecording
Section titled “Platform notes for stopRecording”Android
- When
MediaRecorder.stop()throws,stopRecordingrejects but the file stays on disk. Readerror.data.urianderror.data.duration(milliseconds) from the Capacitor rejection to keep the partial clip. - File names are
recording-yyyyMMdd-HHmmss-<uuid>.m4aor.aac, matchingformat. The UUID keeps two recordings started in the same second from overwriting each other. Earlier versions usedrecording-yyyyMMdd-HHmmss.m4a(no UUID, always.m4a).
import type { StopRecordingResult } from '@capgo/capacitor-audio-recorder';
try { const clip = await CapacitorAudioRecorder.stopRecording(); await upload(clip.uri!, clip.duration);} catch (error: unknown) { const data = (error as { data?: Pick<StopRecordingResult, 'uri' | 'duration'> }).data; if (data?.uri) { await upload(data.uri, data.duration); } else { throw error; }}iOS
- Interrupted
'aac'recordings are merged into one.aacwhen joining succeeds. - When joining fails (for example disk full),
stopRecordingcan resolve withmergeFailed: true, a fallbackuri, andsegments: string[]listing every segment in order. For'aac', do not blindly concatenate raw files: a segment can end with an incomplete ADTS frame, and naive concatenation can break playback of what follows. Copy only complete frames from each segment (the plugin’s join logic does this), or upload each segment separately and stitch server-side. For'm4a', segments cannot be joined by concatenation; remux them or stitch them server-side. - When finalization fails with no usable fallback segment,
stopRecordingrejects but segment files remain on disk.
const result = await CapacitorAudioRecorder.stopRecording();if (result.mergeFailed && result.segments?.length) { console.warn('Join failed, segments on disk', result.segments, result.uri);}startRecording now rejects when AVAudioRecorder.record() returns false (for example the mic is in use elsewhere) instead of returning an empty take.
Example: voice memo with pause
Section titled “Example: voice memo with pause”await CapacitorAudioRecorder.startRecording();// user taps pause during a long noteawait CapacitorAudioRecorder.pauseRecording();await CapacitorAudioRecorder.resumeRecording();const clip = await CapacitorAudioRecorder.stopRecording();pauseRecording is available on Android (API 24+), iOS, and Web.
Example: live level meter
Section titled “Example: live level meter”Poll getCurrentAmplitude() on a timer (about 60 to 100 ms) while status is RECORDING. Values are normalized 0 to 1, but the underlying signal differs by platform (peak on Android, average power on iOS, RMS on Web). Apply a small per platform scale if you need visual parity.
const tick = async () => { const { status } = await CapacitorAudioRecorder.getRecordingStatus(); if (status !== 'RECORDING') return; const { value } = await CapacitorAudioRecorder.getCurrentAmplitude(); updateMeterUi(value);};Example: discard a take
Section titled “Example: discard a take”await CapacitorAudioRecorder.startRecording();await CapacitorAudioRecorder.cancelRecording(); // no file persistedCommon pitfalls
Section titled “Common pitfalls”- Web vs native return shape: Android and iOS return
urifromstopRecording. Web returnsblob(and may omituri). - Crash safety vs default format: only
format: 'aac'on Android and iOS keeps audio playable after a hard stop. Default.m4aneeds a cleanstopRecordingto stay readable. - Failed stop on Android: handle
stopRecordingrejections and readerror.dataforurianddurationinstead of assuming the file was deleted. - Android file names: do not parse the old
recording-yyyyMMdd-HHmmss.m4apattern. Current files include a UUID and may end in.aacwhen you opt intoformat: 'aac'. - iOS merge failures: when
mergeFailedis true, usesegmentsor the fallbackurifrom the resolved result. - Quiet playback on iOS after recording: set
resetToPlaybackOnStop: trueinstartRecordingif users play back the clip inside the same session. - Background capture: the plugin does not enable background audio by itself. On iOS, add the Audio background mode when you need recording while locked.
- Do not spam amplitude: each
getCurrentAmplitudecall crosses the bridge. Use a UI interval, not a tight loop.
API Overview
Section titled “API Overview”startRecording
Section titled “startRecording”Start recording audio using the device microphone.
import { CapacitorAudioRecorder } from '@capgo/capacitor-audio-recorder';
await CapacitorAudioRecorder.startRecording();pauseRecording
Section titled “pauseRecording”Pause the ongoing recording. Only available on Android (API 24+), iOS, and Web.
import { CapacitorAudioRecorder } from '@capgo/capacitor-audio-recorder';
await CapacitorAudioRecorder.pauseRecording();resumeRecording
Section titled “resumeRecording”Resume a previously paused recording.
import { CapacitorAudioRecorder } from '@capgo/capacitor-audio-recorder';
await CapacitorAudioRecorder.resumeRecording();stopRecording
Section titled “stopRecording”Stop the current recording and persist the recorded audio.
On Android, when the recorder cannot stop cleanly, the call is rejected and the recording file is kept on disk. The rejection’s data.uri points to it and data.duration reports elapsed time.
On iOS, when the segments of an interrupted 'aac' recording cannot be joined but a fallback segment exists, the call resolves with mergeFailed and segments. When finalization fails with no fallback segment, the call is rejected and segment files remain on disk.
import { CapacitorAudioRecorder } from '@capgo/capacitor-audio-recorder';
const result = await CapacitorAudioRecorder.stopRecording();console.log(result);cancelRecording
Section titled “cancelRecording”Cancel the current recording and discard any captured audio.
import { CapacitorAudioRecorder } from '@capgo/capacitor-audio-recorder';
await CapacitorAudioRecorder.cancelRecording();getRecordingStatus
Section titled “getRecordingStatus”Retrieve the current recording status.
import { CapacitorAudioRecorder } from '@capgo/capacitor-audio-recorder';
const result = await CapacitorAudioRecorder.getRecordingStatus();console.log(result);getCurrentAmplitude
Section titled “getCurrentAmplitude”Retrieve the current input amplitude (microphone level) as a normalized
number in the [0, 1] range.
Intended for driving live visualizations such as VU meters or waveforms
while recording. Returns 0 when no recording is active. Designed for
UI-rate polling. A 60 to 100 ms interval is a good starting point for a
waveform. Avoid calling it in a tight loop; each call crosses the
JS/native bridge.
import { CapacitorAudioRecorder } from '@capgo/capacitor-audio-recorder';
const result = await CapacitorAudioRecorder.getCurrentAmplitude();console.log(result);checkPermissions
Section titled “checkPermissions”Return the current permission state for accessing the microphone.
import { CapacitorAudioRecorder } from '@capgo/capacitor-audio-recorder';
const result = await CapacitorAudioRecorder.checkPermissions();console.log(result);requestPermissions
Section titled “requestPermissions”Request permission to access the microphone.
import { CapacitorAudioRecorder } from '@capgo/capacitor-audio-recorder';
const result = await CapacitorAudioRecorder.requestPermissions();console.log(result);Type Reference
Section titled “Type Reference”StartRecordingOptions
Section titled “StartRecordingOptions”Options accepted by .
export interface StartRecordingOptions { /** * The audio session category options for recording. Only available on iOS. * * @since 1.0.0 */ audioSessionCategoryOptions?: AudioSessionCategoryOption[];
/** * The audio session mode for recording. Only available on iOS. * * @since 1.0.0 */ audioSessionMode?: AudioSessionMode;
/** * The audio bit rate in bytes per second. * Only available on Android and iOS. * * @since 1.0.0 */ bitRate?: number;
/** * The audio sample rate in Hz. * Only available on Android and iOS. * * @since 1.0.0 */ sampleRate?: number;
/** * When `true`, reset the iOS `AVAudioSession` category to `.playback` when recording stops or is canceled. * * @since 8.2.10 */ resetToPlaybackOnStop?: boolean;
/** * The container the recording is written in. Only available on Android and iOS. * * @default 'm4a' * @since 8.4.0 */ format?: RecordingFormat;}RecordingFormat
Section titled “RecordingFormat”export type RecordingFormat = 'm4a' | 'aac';StopRecordingResult
Section titled “StopRecordingResult”Result returned by .
export interface StopRecordingResult { /** * The recorded audio as a Blob. Only available on Web. * * @since 1.0.0 */ blob?: Blob;
/** * The duration of the recording in milliseconds. * * @since 1.0.0 */ duration?: number;
/** * The URI pointing to the recorded file. Only available on Android and iOS. * * @since 1.0.0 */ uri?: string;
/** * `true` when the segments of an interrupted recording could not be joined. Only available on iOS. * * @since 8.4.0 */ mergeFailed?: boolean;
/** * Segment URIs in recording order when `mergeFailed` is `true`. Only available on iOS. * * @since 8.4.0 */ segments?: string[];}GetRecordingStatusResult
Section titled “GetRecordingStatusResult”Result returned by .
export interface GetRecordingStatusResult { /** * The current recording status. * * @since 1.0.0 */ status: RecordingStatus;}GetCurrentAmplitudeResult
Section titled “GetCurrentAmplitudeResult”Result returned by .
export interface GetCurrentAmplitudeResult { /** * The current input amplitude normalized to the `[0, 1]` range, where `0` * represents silence and `1` represents the maximum level the platform can * report. The value is `0` when no recording is active. * * Note: the source signal differs between platforms. Android reports the * peak sample amplitude since the last call, iOS reports the average power * in dB converted to linear, and Web reports the RMS of the latest frame. * Consumers that need cross-platform parity may want to apply a * per-platform scaling curve. * * @since 8.1.0 */ value: number;}PermissionStatus
Section titled “PermissionStatus”Permission information returned by and .
export interface PermissionStatus { /** * The permission state for audio recording. * * @since 1.0.0 */ recordAudio: PermissionState;}RecordingErrorEvent
Section titled “RecordingErrorEvent”Event emitted when an error occurs during recording.
export interface RecordingErrorEvent { /** * The error message. * * @since 1.0.0 */ message: string;}RecordingStoppedEvent
Section titled “RecordingStoppedEvent”Event emitted when a recording completes.
export type RecordingStoppedEvent = StopRecordingResult;AudioSessionCategoryOption
Section titled “AudioSessionCategoryOption”Audio session category options available on iOS.
export enum AudioSessionCategoryOption { AllowAirPlay = 'ALLOW_AIR_PLAY', AllowBluetooth = 'ALLOW_BLUETOOTH', AllowBluetoothA2DP = 'ALLOW_BLUETOOTH_A2DP', DefaultToSpeaker = 'DEFAULT_TO_SPEAKER', DuckOthers = 'DUCK_OTHERS', InterruptSpokenAudioAndMixWithOthers = 'INTERRUPT_SPOKEN_AUDIO_AND_MIX_WITH_OTHERS', MixWithOthers = 'MIX_WITH_OTHERS', OverrideMutedMicrophoneInterruption = 'OVERRIDE_MUTED_MICROPHONE_INTERRUPTION',}AudioSessionMode
Section titled “AudioSessionMode”Audio session modes available on iOS.
export enum AudioSessionMode { Default = 'DEFAULT', GameChat = 'GAME_CHAT', Measurement = 'MEASUREMENT', SpokenAudio = 'SPOKEN_AUDIO', VideoChat = 'VIDEO_CHAT', VideoRecording = 'VIDEO_RECORDING', VoiceChat = 'VOICE_CHAT',}RecordingStatus
Section titled “RecordingStatus”The recording status.
export enum RecordingStatus { Inactive = 'INACTIVE', Recording = 'RECORDING', Paused = 'PAUSED',}PermissionState
Section titled “PermissionState”Platform permission states supported by Capacitor.
export type PermissionState = 'prompt' | 'prompt-with-rationale' | 'granted' | 'denied';Source Of Truth
Section titled “Source Of Truth”This page is generated from the plugin’s src/definitions.ts. Re-run the sync when the public API changes upstream.
Keep going from Getting Started
Section titled “Keep going from Getting Started”If you are using Getting Started to plan native media and interface behavior, connect it with Using @capgo/capacitor-audio-recorder for the native capability in Using @capgo/capacitor-audio-recorder, Using @capgo/capacitor-live-activities for the native capability in Using @capgo/capacitor-live-activities, @capgo/capacitor-live-activities for the implementation detail in @capgo/capacitor-live-activities, Using @capgo/capacitor-video-player for the native capability in Using @capgo/capacitor-video-player, and @capgo/capacitor-video-player for the implementation detail in @capgo/capacitor-video-player.