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
-
Node.js 18 or later
Ionic 8 and Angular 20 require Node.js 18+ for stable builds.
Check your version with:node -v -
Ionic CLI (latest version)
Install or update the Ionic CLI globally:npm install -g @ionic/cli -
Angular CLI (latest version)
You’ll use Angular CLI for code generation and testing:npm install -g @angular/cli -
Capacitor CLI (v6 or newer)
Capacitor handles native Android and iOS builds:npm install -g @capacitor/cli -
A Code Editor
Visual Studio Code is recommended, with extensions for Ionic, Angular, and TypeScript syntax highlighting. -
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.
-
-
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.

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
-
Enable USB Debugging on your phone.
-
Connect via USB.
-
Android Studio should detect your device.
-
Press Run ▶.
▶️ To run on an emulator
-
Open Device Manager in Android Studio.
-
Create a device (Pixel recommended).
-
Run the emulator.
-
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
-
Select the simulator device from the toolbar.
-
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
-
Connect your iPhone via USB.
-
Trust the device in macOS/iCloud.
-
Select your device in Xcode.
-
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:
- Ionic - Build iOS, Android & Web Apps with Ionic & Angular
- Master Ionic 8+: Beginner to Expert Food Delivery App Course
- Ionic 8+ Masterclass:Build Real-Time Chat Apps with Firebase
- Ionic 8+ & Supabase Full-Stack Mastery: Build Real-Time Apps
- Learn Ionic React By Building a WhatsApp Clone
- Progressive Web Apps (PWA) - The Complete Guide
- IONIC - Build Android & Web Apps with Ionic
- Ionic Framework with VueJS: Build a CRUD App Using SQLite
- Angular, Ionic & Node: Build A Real Web & Mobile Chat App
- Ionic Apps with Firebase
Thanks!
