DEV Community

Cover image for Lets create a screen recorder with JS
Shuvo
Shuvo

Posted on

Lets create a screen recorder with JS

OBS studio is cool but lets create our very own screen recorder using JavaScript.
And guess what? Its not limited to just recording the browser screen. Yes, you've read that right. Although JavaScript runs on browser, we can use JS to record not only the active tab but any tab or entire screen. So lets get started.
First thing we'd need is a HTML file, in that we will have a record button and a video element where we can play the recorded video.

<!DOCTYPE html>
<html>
  <head>
    <title>Parcel Sandbox</title>
    <meta charset="UTF-8" />
  </head>
  <body>
    <video class="video" width="600px" controls></video>
    <button class="record-btn">record</button>

    <script src="./index.js"></script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

And we'd also need a JS file so lets create the index.js also

let btn = document.querySelector(".record-btn");

btn.addEventListener("click", function () {
  console.log("hello");
});

Enter fullscreen mode Exit fullscreen mode

So now if we open it the browser and click on the button we should see hello in console.

Alright now instead of console.log lets get the stream of users display

let btn = document.querySelector(".record-btn");

btn.addEventListener("click", async function () {
  let stream = await navigator.mediaDevices.getDisplayMedia({
    video: true
  });
});
Enter fullscreen mode Exit fullscreen mode

So now if you click on the button you'll see this popup.
screen record popup

Now you might think we are done select a window or screen and click share and it should start recording. But its a bit more complicated than that. We have to record the video our self. We are going to use MediaRecorder to record our video.

let btn = document.querySelector(".record-btn")

btn.addEventListener("click", async function () {
  let stream = await navigator.mediaDevices.getDisplayMedia({
    video: true
  })

  //needed for better browser support
  const mime = MediaRecorder.isTypeSupported("video/webm; codecs=vp9") 
             ? "video/webm; codecs=vp9" 
             : "video/webm"
    let mediaRecorder = new MediaRecorder(stream, {
        mimeType: mime
    })

    //we have to start the recorder manually
    mediaRecorder.start()
})
Enter fullscreen mode Exit fullscreen mode

So as our screen get recorded mediaRecorder will give us data in chunks we need to store those data in a variable.

let btn = document.querySelector(".record-btn")

btn.addEventListener("click", async function () {
  let stream = await navigator.mediaDevices.getDisplayMedia({
    video: true
  })

  //needed for better browser support
  const mime = MediaRecorder.isTypeSupported("video/webm; codecs=vp9") 
             ? "video/webm; codecs=vp9" 
             : "video/webm"
    let mediaRecorder = new MediaRecorder(stream, {
        mimeType: mime
    })

    let chunks = []
    mediaRecorder.addEventListener('dataavailable', function(e) {
        chunks.push(e.data)
    })

    //we have to start the recorder manually
    mediaRecorder.start()
})
Enter fullscreen mode Exit fullscreen mode

And now when we click on the stop sharing button we want the recorded video to be played in our video element so lets do that.

let btn = document.querySelector(".record-btn")

btn.addEventListener("click", async function () {
  let stream = await navigator.mediaDevices.getDisplayMedia({
    video: true
  })

  //needed for better browser support
  const mime = MediaRecorder.isTypeSupported("video/webm; codecs=vp9") 
             ? "video/webm; codecs=vp9" 
             : "video/webm"
    let mediaRecorder = new MediaRecorder(stream, {
        mimeType: mime
    })

    let chunks = []
    mediaRecorder.addEventListener('dataavailable', function(e) {
        chunks.push(e.data)
    })

    mediaRecorder.addEventListener('stop', function(){
      let blob = new Blob(chunks, {
          type: chunks[0].type
      })

      let video = document.querySelector(".video")
      video.src = URL.createObjectURL(blob)
  })

    //we have to start the recorder manually
    mediaRecorder.start()
})
Enter fullscreen mode Exit fullscreen mode

Now as a finishing touch lets automatically download the recorded video.

let btn = document.querySelector(".record-btn")

btn.addEventListener("click", async function () {
  let stream = await navigator.mediaDevices.getDisplayMedia({
    video: true
  })

  //needed for better browser support
  const mime = MediaRecorder.isTypeSupported("video/webm; codecs=vp9") 
             ? "video/webm; codecs=vp9" 
             : "video/webm"
    let mediaRecorder = new MediaRecorder(stream, {
        mimeType: mime
    })

    let chunks = []
    mediaRecorder.addEventListener('dataavailable', function(e) {
        chunks.push(e.data)
    })

    mediaRecorder.addEventListener('stop', function(){
      let blob = new Blob(chunks, {
          type: chunks[0].type
      })
      let url = URL.createObjectURL(blob)

      let video = document.querySelector("video")
      video.src = url

      let a = document.createElement('a')
      a.href = url
      a.download = 'video.webm'
      a.click()
  })

    //we have to start the recorder manually
    mediaRecorder.start()
})
Enter fullscreen mode Exit fullscreen mode

And there now we have a fully functional screen recorder app.

Make sure to read my other articles.

0shuvo0 image

Discussion (40)

Collapse
landb profile image
Branko Stancevic • Edited on

Great article! Keep it up! However, I have question...

Why you need to create chunks when e.data in dataavailable is already a blob?

Isn't that part kinda unnecessary?

Couldn't we just use it like this?

  let blob = null;

  mediaRecorder.addEventListener('dataavailable', (e) => {
    blob = e.data;
  })
Enter fullscreen mode Exit fullscreen mode
Collapse
0shuvo0 profile image
Shuvo Author

as you keep recording the dataavailable event will run multiple time. So basically instead you giving you the entire video once recording is done it will give you data in small parts as the video is being recorded.

Collapse
landb profile image
Branko Stancevic

Ok cool! Thank you

Collapse
amk profile image
Amran AL Ketara

YOU ARE AWESOME MAN!!
Do you have a YouTube channel, blog or something like that?

Collapse
0shuvo0 profile image
Shuvo Author

Many many Thank.
Yes, I have a YouTube channel.
But I am introvert so I struggle to talk which is why my videos are not that good. But I'm trying to improve
youtu.be/mD_QQvJYQAI

Collapse
monfernape profile image
Usman Khalil

Very clear explanation. Loved it

Collapse
0shuvo0 profile image
Shuvo Author

Many many Thanks

Collapse
monfernape profile image
Usman Khalil

The minute I saw the tutorial, the next thing I knew was that I'm gonna make this thing my self. Created in React and deployed. Thank you once again.

Thread Thread
0shuvo0 profile image
Shuvo Author

Damn thats really great.
If you want something way more challenging you can try this

Thread Thread
monfernape profile image
Usman Khalil

Damn. You just earned a follower and my respect. Keep those challenges coming coach.

Thread Thread
0shuvo0 profile image
Shuvo Author

Thanks a lot.
I also followed you back.

Collapse
jafb321 profile image
Jose Antonio Felix

It's pretty cool !!! thank you man

Collapse
0shuvo0 profile image
Shuvo Author

You're most welcome

Collapse
aboss123 profile image
Ashish Bailkeri

Nice tutorial!

Collapse
0shuvo0 profile image
Shuvo Author

I'm really glad that you liked it.

Collapse
mustafatoprakk profile image
mustafatoprakk

Thank you buddy. İt's very beautiful

Collapse
0shuvo0 profile image
Shuvo Author

Many Thanks I am glad you liked it

Collapse
prabhukadode profile image
Prabhu

Nice

Collapse
0shuvo0 profile image
Shuvo Author

Thank you

Collapse
iacons profile image
Iacovos Constantinou

That's really great!!

Collapse
0shuvo0 profile image
Shuvo Author

Glad you found this helpful

Collapse
honzaled profile image
HonzaLed

Nice tutorial, i was wondering how to do this, your step-by-step tutorial is awesome

Collapse
0shuvo0 profile image
Shuvo Author

I am really glad that you liked it

Collapse
bias profile image
Tobias Nickel

awesome, this is a great extension to all the zoom clone tutorials 👍

Collapse
0shuvo0 profile image
Shuvo Author

Glad you liked it

Collapse
dvlprroshan profile image
Roshan kumar

Really awesome tutorial !

Collapse
0shuvo0 profile image
Shuvo Author

I am glad you liked it.

Collapse
nicenine98 profile image
nicenine98

hello
I am web developer. I have to build new site.
but I have to capture image from stream-video when user click capture button.
Also I have to extract from that images.
Help me.

Collapse
0shuvo0 profile image
Shuvo Author
Collapse
d1_codes profile image
d1_codes

Great Tutorial here.. Please i cant fin where the recorded files are been saved.

Collapse
0shuvo0 profile image
Shuvo Author

In your downloads folders.

Collapse
qq449245884 profile image
qq449245884

Dear Shupvo,may I translate your all dev articles into Chinese?I would like to share it with more developers in China. I will give the original author and original source.

Collapse
0shuvo0 profile image
Shuvo Author

Sure, You're most welcome

Collapse
suhakim profile image
sadiul hakim

wow

Collapse
mena234 profile image
Mena Nasser • Edited on

Very nice article, thank you.

Collapse
0shuvo0 profile image
Shuvo Author

Yes
developers.google.com/web/fundamen...
But its hard to to both at once

Collapse
pramon18 profile image
pramon18

This was a good article. Step by step articles like this are really a good idea. Good Job.

Collapse
0shuvo0 profile image
Shuvo Author

Many thanks, I apprecate your valuable comment a loy

Collapse
yosi profile image
yosi

Great post. Thank you!

Collapse
0shuvo0 profile image
Shuvo Author

Glad you liked it