How Capture, Save and Play Videos with Capacitor inside PWAs [v5]


If you want to build a PWA with video capturing capabilities, you are lucky since the MediaRecorder API is now available in almost every browser!

In this Quick Win we will implement a PWA that can capture, store and play videos. Be aware that the approach won’t work inside a native app and only inside the browser/PWA, but you can easily fall back to Cordova plugins for a real app if you want to.

You can also check out and test the PWA yourself here.


To finally play our video files we will also use the Capacitor Video player plugin.

Starting our Video Capture App

To get started create a new Ionic app with Capacitor enabled. Then we need to install the typings for the Media recorder to correctly use it with Typescript and also the Capacitor plugin for our video player.

Finally add the PWA schematics so you can easily build and test the app later:

In order to use the installed typings correctly I also had to modify the and add it to the types array:

The rest is pure web technology so let’s dive in!

Storing & Loading Videos with Capacitor

Before we really capture the videos, we create a bit of logic to keep track of our videos. We will store the files inside the Filesystem of the app, and we store the path to our files inside the Capacitor storage.

To store the video, which is a blob, we need to first convert it to a base64 string using a helper function.

Once we got the base64 data we can write it to the filesystem, add the path to the file to our local videos array and also save the information to the storage.

Now go ahead and change the services/video.service.ts to:

At the end we also got a function to get the video, because the player won’t play the video from the file URL directly (or I didn’t found the right way). But we can easily load the file from the path that we stored, and then return the file data as the correct base64 string back.

Creating the Video Capture View

With our logic in place we can continue to the implementation of our capturing. The basic idea is to get a stream of video data, which we can display in a viewchild in our template later.

We can then use the MediaRecorder API with the stream we created, which can then be used to capture chunks of data inside the ondataavailable. This means, we can store these chunks of data while the video capturing is in progress, and once we end the capturing we enter the onstop function.

Here we can use the previously created array of video data chunks to create a new blob and then pass this blob to our service, which will handle the storing of that file.

The last function to play a video also makes use of our service to get the base64 data of a video from the path of the video file, and the player plugin we installed handles the rest.

Now open the home/ and change it to:

To finally make everything work we need a special video element which acts as the viewchild and displays the stream of the video while capturing.

Additionally we need a special div for the video player, which is required by the plugin!

Finally our list displays all the captured and stored videos with a play function, and the fab button is used both for starting and stopping the recording by using the isRecording variable that we toggle in our class.

Open the home/ and change it to this now:

As a final fix I also had to give the video element a specific size to make it visible on all browser, but feel free to play around with those values inside the home/

You can now test your app locally with serve or deploy it as a PWA for example to Firebase!

If you experience problems on iOS or Safari on a mac, you need to enable the Mediarecorder API which was still marked as experimental at the time writing and turned off by default!


The same setting can be found on iOS inside Settings -> Safari -> Advanced -> Experimental Features!


The web is making progress every year, and although iOS is sometimes a bit behind, the MediaRecorder API should be enabled by default pretty soon!

Keep in mind that this will now only work inside a PWA, for a native app through the app store you should use the according Cordova / Capacitor plugins instead.

You can also find a video version of this Quick Win below.