Record and Play Sound in Ionic 8, Angular 20, and Capacitor Mobile App

by Didin J. on Nov 06, 2025 Record and Play Sound in Ionic 8, Angular 20, and Capacitor Mobile App

Learn how to record and play audio using Ionic 8, Angular 20, and Capacitor. Updated 2025 guide with modern plugins, UI, permissions, and device setup.

Recording and playing audio directly from a mobile app has become a standard feature in many modern applications — from voice memos and podcast apps to chat and reporting tools. In 2017, we developed this feature using Ionic 3, Angular 5, and Cordova plugins. However, with today’s technology, the Ionic ecosystem has evolved dramatically — bringing a cleaner architecture, native performance improvements, and modern APIs through Capacitor.

In this 2025 update, we’ll rebuild the Record and Play Sound app using the latest Ionic 8, Angular 20, and Capacitor 6 (the native runtime replacing Cordova). This version offers enhanced native integration, improved permission handling, and compatibility with the latest Android and iOS SDKs.

You’ll learn how to:

  • Create a new Ionic 8 + Angular 20 project with Capacitor

  • Install and configure an audio recording and playback plugin

  • Build an intuitive UI using the latest Ionic components

  • Handle permissions for microphone access on Android and iOS

  • Record, store, and play back audio files on your device

By the end of this tutorial, you’ll have a fully functional mobile app capable of recording and playing audio files, built with modern Ionic and Angular best practices — and without relying on outdated Cordova APIs.


Prerequisites

Before diving into building the app, make sure your development environment is ready for Ionic 8, Angular 20, and Capacitor 6. The setup process is straightforward, but using the correct versions ensures compatibility across your dependencies and mobile platforms.

Requirements

  1. Node.js 18 or later
    Ionic 8 and Angular 20 require Node.js 18+ for stable builds.
    Check your version with:

     
    node -v

     

  2. Ionic CLI (latest version)
    Install or update the Ionic CLI globally:

     
    npm install -g @ionic/cli

     

  3. Angular CLI (latest version)
    You’ll use Angular CLI for code generation and testing:

     
    npm install -g @angular/cli

     

  4. Capacitor CLI (v6 or newer)
    Capacitor handles native Android and iOS builds:

     
    npm install -g @capacitor/cli

     

  5. A Code Editor
    Visual Studio Code is recommended, with extensions for Ionic, Angular, and TypeScript syntax highlighting.

  6. Android Studio / Xcode
    You’ll need:

    • Android Studio (for Android builds)

    • Xcode (for iOS builds, macOS only)
      These tools provide native emulators and SDKs for deploying your app to devices.

  7. Basic Knowledge Requirements

    • TypeScript and ES2022 syntax

    • Angular services and components

    • Ionic UI components and routing

    • Understanding of Capacitor plugins and permissions

Optional Tools

  • Ionic DevApp or Ionic Lab for multi-platform preview

  • Postman or REST Client (if later extending the app with uploads)

  • Git for version control

With everything installed, we’re ready to scaffold the Ionic 8 and Angular 20 app using the Ionic CLI.

 

Create a New Ionic 8 Angular 20 Project with Capacitor

In this section, we’ll set up a fresh Ionic 8 + Angular 20 project integrated with Capacitor 6. This will serve as the foundation for our sound recording and playback app.

Step 1: Create a New Ionic Project

Run the following command to generate a new blank Ionic app using Angular as the framework:

ionic start sound-recorder blank --type=angular

Next, open and edit `src/app/app.module.ts` then add these imports of Ionic Native Media and File.

import { Media } from '@ionic-native/media';
import { File } from '@ionic-native/file';

When prompted:

  • Framework: Choose Angular

  • Starter template: Choose blank

  • Add Capacitor? Choose Yes

Once created, navigate into your project directory:

cd sound-recorder

Step 2: Verify Ionic and Angular Versions

Check that you’re running the latest versions compatible with Ionic 8 and Angular 20:

ionic info

You should see output similar to:

Ionic CLI : 7.x.x
Ionic Framework : 8.x.x
Angular Core : 20.x.x
Capacitor CLI : 6.x.x
Node.js : 18.x.x

If you see older versions, update dependencies in package.json and reinstall with:

npm install

Step 3: Initialize Capacitor (if not done already)

If you skipped adding a Capacitor during project creation, initialize it manually:

npx cap init

Follow the prompts:

  • App name: Sound Recorder

  • App ID: com.example.soundrecorder

Then install Capacitor core packages:

npm install @capacitor/core @capacitor/cli

Step 4: Add Mobile Platforms

Add Android and iOS platforms to your project:

npm install @capacitor/android
npx cap add android
npm install @capacitor/ios
npx cap add ios

This command generates two folders:

  • android/ for Android Studio

  • ios/ for Xcode

If you don’t have Xcode installed, you can skip the iOS step for now.

Step 5: Run the App in the Browser

Before diving into plugins, confirm that everything works:

ionic serve

You should see the default blank Ionic app running in your browser at http://localhost:8100.

Record and Play Sound in Ionic 8, Angular 20, and Capacitor Mobile App - ionic serve

Step 6: Sync and Build for Native Platforms

Whenever you make changes or add new dependencies, sync them to Capacitor platforms:

ionic build
npx cap copy
npx cap sync

Then open your project in Android Studio or Xcode:

npx cap open android
npx cap open ios

At this stage, you have a fully configured Ionic 8 + Angular 20 + Capacitor 6 app that can run on Android, iOS, or the web.


Install and Configure Audio Recording/Playback Plugins

Now that our Ionic 8 + Angular 20 + Capacitor app is ready, let’s add functionality to record and play sound.
In older Ionic versions, this was achieved with Cordova Media and Media Capture plugins. However, in 2025, we’ll use modern Capacitor plugins and the Web Audio API for better compatibility and performance.

Step 1: Choose an Audio Plugin

As of Capacitor 6, the recommended approach is to use @capacitor-community/media for native audio recording and playback.

Install it using npm:

npm install capacitor-voice-recorder
npx cap sync

This plugin allows you to:

  • Record audio directly from the device’s microphone

  • Save audio files locally

  • Play back recorded audio

Step 2: Configure Platform Permissions

Recording audio requires a microphone and storage permissions on both Android and iOS.

Android

Edit android/app/src/main/AndroidManifest.xml and add:

<uses-permission android:name="android.permission.RECORD_AUDIO" />

Starting from Android 13 (API 33+), you must request permissions at runtime.
We’ll handle that later in the service layer.

iOS

Open ios/App/App/Info.plist and add:

<key>NSMicrophoneUsageDescription</key>
<string>This app requires access to the microphone to record audio.</string>

This ensures your app passes Apple’s permission checks.

Step 3: Install an Optional Web Fallback (Browser Support)

The Capacitor Media plugin works great on mobile, but to test in a browser, we can use the Web Audio API and MediaRecorder.

Install TypeScript type definitions for web recording:

npm install --save-dev @types/dom-mediacapture-record

This will help TypeScript recognize browser APIs like MediaRecorder and Blob.

Step 4: Create an Audio Folder (Optional)

If you plan to store recordings locally, create a directory using Capacitor’s Filesystem API:

npm install @capacitor/filesystem
npx cap sync

Later, we’ll use this to save and retrieve recordings for playback.

Step 5: Verify Plugin Integration

Run the following to confirm Capacitor detects the plugin:

npx cap doctor

You should see @capacitor-community/media listed under Plugins.

Then rebuild your native project:

ionic build
npx cap sync
npx cap open android

Run the app on a device and check that the plugin initializes without errors.

At this point, your Ionic 8 project is fully equipped to handle microphone access and audio storage through Capacitor.


Implement Recording Service in Angular

Now that the audio plugins are installed and configured, it’s time to implement the logic that powers recording and playback.
We’ll create a reusable Angular service that handles:

  • Starting and stopping recordings

  • Saving recorded files

  • Listing available audio files

  • Playing back a selected recording

This separation keeps the UI clean and allows you to reuse the logic elsewhere in your app.

Step 1: Generate the Service

Use the Angular CLI to create a new service:

ng generate service services/sound

This will create src/app/services/sound.ts.

Step 2: Import Dependencies

Open sound.service.ts and import the required Capacitor plugins:

import { Injectable } from '@angular/core';
import {
  VoiceRecorder,
  RecordingData,
  GenericResponse
} from 'capacitor-voice-recorder';
import { Filesystem, Directory, Encoding } from '@capacitor/filesystem';

Step 3: Define Service Variables and State

Add some state to track whether recording is in progress and store a list of recorded files:

@Injectable({
  providedIn: 'root',
})
export class Sound {
  private isRecording = false;
  private recordings: any[] = [];

  constructor() { }
}

Step 4: Start and Stop Recording

Use the Capacitor Media plugin to start and stop audio recording.
Add the following methods inside the SoundService class:

  async requestPermission() {
    const permResult = await VoiceRecorder.requestAudioRecordingPermission();
    return permResult.value;
  }

  async startRecording() {
    const allowed = await this.requestPermission();
    if (!allowed) {
      throw new Error('Microphone permission not granted');
    }

    await VoiceRecorder.startRecording();
    this.isRecording = true;
  }

  async stopRecording() {
    const result: RecordingData = await VoiceRecorder.stopRecording();
    this.isRecording = false;

    if (result.value && result.value.recordDataBase64) {
      const fileName = `rec-${Date.now()}.wav`;
      const base64 = result.value.recordDataBase64;

      const audioUrl = `data:audio/wav;base64,${base64}`;

      this.recordings.push({
        fileName,
        audioUrl,
        base64,
      });

      return audioUrl;
    }

    return null;
  }

Here:

  • Media.recordAudio() begins recording using the device's microphone.

  • Media.stopAudioRecording() stops and returns the file path.

Step 5: Play Recorded Audio

Add a method to play a recorded file:

  async playAudio(recording: any) {
    const audio = new Audio(recording.audioUrl);
    audio.play();
  }

Step 6: Utility Methods

Add helper functions to handle file names and retrieve recordings:

  getRecordings() {
    return this.recordings;
  }

Step 7: Browser Fallback (Optional)

Capacitor plugins won’t work in the browser, so you can optionally use MediaRecorder for development testing:

  private mediaRecorder: any;
  private chunks: Blob[] = [];

  async startWebRecording() {
    const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
    this.mediaRecorder = new MediaRecorder(stream);
    this.chunks = [];

    this.mediaRecorder.ondataavailable = (event: any) => {
      this.chunks.push(event.data);
    };

    this.mediaRecorder.onstop = async () => {
      const blob = new Blob(this.chunks, { type: 'audio/mp3' });
      const url = URL.createObjectURL(blob);
      this.recordings.push({ fileName: `recording-${Date.now()}.mp3`, filePath: url });
    };

    this.mediaRecorder.start();
  }

  stopWebRecording() {
    this.mediaRecorder?.stop();
  }

Use this fallback when running with ionic serve.

Step 8: Save and Retrieve Recordings (Optional)

To persist recordings locally, use the Filesystem API:

  async saveRecording(fileName: string, data: Blob) {
    const base64 = await this.blobToBase64(data);
    await Filesystem.writeFile({
      path: `recordings/${fileName}`,
      data: base64,
      directory: Directory.Data
    });
  }

  private blobToBase64(blob: Blob): Promise<string> {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onerror = reject;
      reader.onload = () => {
        const base64Data = (reader.result as string).split(',')[1];
        resolve(base64Data);
      };
      reader.readAsDataURL(blob);
    });
  }

With this SoundService in place, your app can now record, stop, and play audio files from the device microphone (or from the browser fallback).


Implement UI in Ionic 8 / Angular 20

Now that your audio recording logic is handled by the SoundService, it’s time to build a clean and modern UI using Ionic 8 components.
This section covers:

✅ UI layout
✅ Buttons for recording and stopping
✅ List of recordings
✅ Play button for each recording
✅ Binding Angular logic to the UI

We’ll use the default HomePage generated by Ionic.

Step 1 — Update the Home Page TypeScript File

Open:

src/app/home/home.page.ts

Replace contents with:

import { Component, OnInit } from '@angular/core';
import { IonHeader, IonToolbar, IonTitle, IonContent, IonCard, IonCardContent, IonButton, IonIcon, IonList, IonListHeader, IonLabel, IonItem } from '@ionic/angular/standalone';
import { Sound } from '../services/sound';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
  imports: [IonItem, IonLabel, IonListHeader, IonList, IonIcon, IonButton, IonCardContent, IonCard, IonHeader, IonToolbar, IonTitle, IonContent],
})
export class HomePage implements OnInit {

  isRecording = false;

  constructor(private soundService: Sound) { }

  ngOnInit() { }

  async toggleRecording() {
    if (!this.isRecording) {
      await this.startRecording();
    } else {
      await this.stopRecording();
    }
  }

  async startRecording() {
    try {
      await this.soundService.startRecording();
      this.isRecording = true;
    } catch (err) {
      console.error(err);
    }
  }

  async stopRecording() {
    try {
      await this.soundService.stopRecording();
      this.isRecording = false;
    } catch (err) {
      console.error(err);
    }
  }

  play(rec: any) {
    this.soundService.playAudio(rec);
  }

  get recordings() {
    return this.soundService.getRecordings();
  }
}

This page uses the service to record/stop and provides audio playback.

Step 2 — Create the UI Layout (HTML)

Open:

src/app/home/home.page.html

Replace contents with:

<ion-header>
  <ion-toolbar color="primary">
    <ion-title>Sound Recorder</ion-title>
  </ion-toolbar>
</ion-header>

<ion-content class="ion-padding">
  <ion-card>
    <ion-card-content class="ion-text-center">
      <ion-button
        expand="block"
        color="danger"
        shape="round"
        (click)="toggleRecording()"
      >
        <ion-icon
          slot="start"
          [name]="isRecording ? 'stop-circle' : 'mic-circle'"
        ></ion-icon>

        {{ isRecording ? 'Stop Recording' : 'Start Recording' }}
      </ion-button>
    </ion-card-content>
  </ion-card>

  <ion-list *ngIf="recordings.length > 0">
    <ion-list-header>
      <ion-label>Recordings</ion-label>
    </ion-list-header>

    <ion-item *ngFor="let rec of recordings; index as i">
      <ion-label>{{ rec.fileName }}</ion-label>

      <ion-button slot="end" fill="clear" color="primary" (click)="play(rec)">
        <ion-icon name="play"></ion-icon>
      </ion-button>
    </ion-item>
  </ion-list>
</ion-content>

Modern Ionic 8 components
✅ Clean layout
✅ Dynamically shows all saved audio recordings
✅ Buttons for play / start / stop

Step 3 — Styling (Optional)

home.page.scss

ion-card {
  margin-top: 20px;
}

ion-button {
  font-size: 1.1rem;
}

ion-icon {
  font-size: 1.4rem;
}

You may customize styling further.

Step 4 — Test in Browser (Web Fallback)

Since capacitor-voice-recorder does not work in browser, recordings will only work on Android/iOS.

To avoid errors during browser testing, add a simple guard in your service:

if (!Capacitor.isNativePlatform()) {
  alert('Audio recording works only on a real device.');
  return;
}

Step 5 — Run on Device

Rebuild & sync:

ionic build
npx cap copy
npx cap sync

Open Android Studio or Xcode:

npx cap open android
npx cap open ios

Run on a real device to test recording and playback.

Your UI is now fully connected to the working audio recording service.
The app can:

✅ Record audio
✅ Stop recording
✅ Save recordings in memory
✅ Play audio
✅ Display recording list


Running On Device & Debugging

Now that the UI and audio recording logic are fully implemented, it’s time to test the app on actual mobile devices. Audio recording cannot be tested in the browser because capacitor-voice-recorder only works on native Android/iOS platforms. This section walks through running, testing, and debugging your Ionic 8 + Angular 20 + Capacitor app.

1. Build and Sync with Capacitor

After any significant changes (like adding plugins), run:

ionic build
npx cap copy
npx cap sync

This ensures all web assets and plugin code are synchronized with the native Android and iOS projects.

2. Run on Android Device or Emulator

Open the Android project:

npx cap open android

This opens Android Studio.

▶️ To run on a physical Android device

  1. Enable USB Debugging on your phone.

  2. Connect via USB.

  3. Android Studio should detect your device.

  4. Press Run ▶.

▶️ To run on an emulator

  1. Open Device Manager in Android Studio.

  2. Create a device (Pixel recommended).

  3. Run the emulator.

  4. Press Run ▶ again.

✅ Test microphone permission
✅ Try recording audio
✅ Play back recordings
✅ Check logs for errors

3. Run on iOS Device or Simulator (macOS only)

Open the iOS project:

npx cap open ios

Xcode will open.

▶️ To run on an iOS simulator

  1. Select the simulator device from the toolbar.

  2. Press Build & Run ▶.

⚠️ Note:
iOS Simulators do not support microphone input, so audio recording will NOT work.
Playback may work, but recording will not.

▶️ To run on a real iPhone

  1. Connect your iPhone via USB.

  2. Trust the device in macOS/iCloud.

  3. Select your device in Xcode.

  4. Press Build & Run ▶.

✅ Ensure NSMicrophoneUsageDescription exists in Info.plist
✅ Test recording + playback on physical device
✅ Monitor Xcode logs for plugin issues

4. Testing Permissions

To verify permissions are requested correctly:

Android

Android 12+ requires explicit runtime permission dialogs.
Recording won’t start until permission is granted.

Look in Logcat for messages like:

Permission denied: RECORD_AUDIO

If permission issues occur, add a direct request:

await VoiceRecorder.requestAudioRecordingPermission();

iOS

If your microphone key isn’t set, the app will crash immediately when recording starts.

Ensure your Info.plist contains:

<key>NSMicrophoneUsageDescription</key>
<string>We need microphone access to record audio.</string>

5. Debugging Common Issues

Issue: Recording doesn’t start

✅ Fix: Ensure you’re running on a physical device
✅ Fix: Check permissions using:

await VoiceRecorder.hasAudioRecordingPermission();

Issue: “Plugin not implemented”

This means you are running the app in a browser.

✅ Fix: Run on Android/iOS device
✅ Fix: Add a platform guard:

if (!Capacitor.isNativePlatform()) {
  alert('Recording works only on a native device.');
  return;
}

Issue: Playback shows no sound

✅ Fix: Check that audioUrl starts with data:audio/wav;base64
✅ Fix: Volume or permissions on device
✅ Fix: Audio too short (less than 300ms)

Issue: iOS - App freezes on recording

Usually caused by not calling the plugin on the main thread.

✅ Fix: Update to latest capacitor-voice-recorder
✅ Fix: Rebuild native project with:

npx cap sync ios

6. Use Device Logs for Debugging

Android Logcat

In Android Studio:

  • View → Tool Windows → Logcat

  • Filter by your app package

iOS Xcode Logs

In Xcode:

  • View → Debug Area → Activate Console

These logs help track plugin responses, errors, and permission issues.

7. Testing Tips

✅ Record several short and long samples
✅ Test playback immediately
✅ Try recording with app in background (Android supports, iOS limits)
✅ Test on different devices/OS versions (Android 12+, Android 13+, iOS 16+)

Your app is now running on real devices with full, working audio recording and playback.


Troubleshooting & Notes

Even with the correct plugins and setup, audio recording can behave differently across platforms, devices, and OS versions. This section covers the most common issues you may encounter when building an audio recording app with Ionic 8, Angular 20, and Capacitor 6, along with practical solutions and recommendations.

1. Plugin Not Implemented / Undefined

Symptoms:

  • Console error:

     
    ERROR Error: "plugin_not_implemented"

     

  • Recording does nothing on the device.

  • Works in native builds but not in the browser.

Cause:
capacitor-voice-recorder only works on native platforms.

Fix:
Guard your recording actions:

import { Capacitor } from '@capacitor/core';

if (!Capacitor.isNativePlatform()) {
  alert('Audio recording works only on a real mobile device.');
  return;
}

2. Microphone Permission Issues

Android

If users deny permission or if RECORD_AUDIO was not added to AndroidManifest.xml, recording will fail silently.

Check permission programmatically:

const hasPerm = await VoiceRecorder.hasAudioRecordingPermission();

If false:

await VoiceRecorder.requestAudioRecordingPermission();

iOS

Missing NSMicrophoneUsageDescription causes an instant crash when accessing the microphone.

Add to Info.plist:

<key>NSMicrophoneUsageDescription</key>
<string>We need microphone access to record audio.</string>

3. Audio Playback Has No Sound

Causes:

  • File saved incorrectly

  • Data URL malformed

  • Audio base64 not formatted properly

Verify the final URL:

console.log(recording.audioUrl);

It must start with:

data:audio/wav;base64,

4. Recording Too Short or Empty

Some Android devices discard recordings shorter than 300–500ms.

✅ Try recording longer audio
✅ Add a minimal recording timer (optional)

5. iOS Simulator Does NOT Support Microphone

Recording will never work on the iOS simulator.

✅ Must test on a real iPhone or iPad

Playback does work, but recording does not.

6. Android 12/13 Permission Changes

Android 12+ and 13+ introduced stricter microphone handling.

If recording silently fails:

✅ Ensure your targetSdkVersion is 33+
✅ Add runtime permission requests
✅ Check Android Studio’s Logcat for:

E/AudioRecord: start() status -38

7. App Crashes Immediately on Recording

Most common on iOS.

Causes:

  • Missing permission key

  • Old version of capacitor-voice-recorder

  • Attempting plugin call before platform.ready()

Fix:

Update plugin:

npm install capacitor-voice-recorder@latest
npx cap sync

Ensure app waits for Capacitor platform:

import { Platform } from '@ionic/angular';

constructor(private platform: Platform) {
  this.platform.ready().then(() => {
    console.log('Platform ready');
  });
}

8. Background Recording Limitations

  • Android: Generally supported (but depends on OEM).

  • iOS: Not allowed unless your app declares background audio mode (not recommended unless required).

9. File Persistence

Currently, recordings are kept in memory only.

For persistent storage:

✅ Use Capacitor Filesystem
✅ Save base64 to a .wav file
✅ Load the files on the next app startup

I can provide a full persistent storage section if you’d like.

10. Debugging Plugin Responses

Android (Logcat)

Filter logs:

VoiceRecorder
AudioRecord
Capacitor

iOS (Xcode)

Watch logs under:

Debug Area → Console

Look for plugin errors or permission warnings.

11. Plugin Limitations (Important)

capacitor-voice-recorder is great but has limits:

⚠ No built-in pause/resume
⚠ Only outputs WAV or PCM formats
⚠ No audio trimming
⚠ No automatic file management

For advanced audio features, you may need:

  • Native Swift/Kotlin code

  • A more advanced plugin

  • Web Audio processing

Your tutorial now includes a comprehensive troubleshooting section that will greatly help users avoid common pitfalls and understand platform-specific behaviors.


Conclusion

In this updated 2025 version of the tutorial, you’ve learned how to build a fully functional sound recording and playback app using the modern Ionic ecosystem—Ionic 8, Angular 20, and Capacitor 6. Unlike the older Ionic 3 + Cordova approach, today’s stack offers cleaner APIs, better native integration, and significantly improved performance across Android and iOS.

Here’s what we achieved:

✅ Created a fresh Ionic 8 project with Angular 20
✅ Added and configured Capacitor platforms (Android/iOS)
✅ Implemented audio recording using the modern capacitor-voice-recorder plugin
✅ Built a clean UI with Ionic components for recording, stopping, listing, and playing audio
✅ Implemented browser guards and mobile permission handling
✅ Ran and debugged the app on real devices
✅ Covered essential troubleshooting and platform-specific issues

This new approach is future-proof, Cordova-free, and aligned with current best practices for mobile audio features in hybrid applications.

With the foundation in place, you can now extend the app further by adding:

✨ Saving recordings to the filesystem
✨ Uploading audio to Firebase or a backend API
✨ Sharing audio files with the Capacitor Share plugin
✨ Adding audio trimming, waveform visualization, or noise reduction
✨ Implementing folders, timestamps, or metadata

Whether you’re building a voice memo app, a podcasting tool, or embedding voice messaging inside a larger application, this setup gives you a modern, scalable baseline to build upon.

You can find the working source code on our GitHub.

We know that building beautifully designed Ionic apps from scratch can be frustrating and very time-consuming. Check Ionic 6 - Full Starter App and save development and design time. Android, iOS, and PWA, 100+ Screens and Components, the most complete and advanced Ionic Template.

That's just the basics. If you need more deep learning about Ionic, Angular, and TypeScript, you can take the following cheap course:

Thanks!