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

Latest comments (49)

Collapse
 
pixelcrash profile image
Georg Kettele

Hi there, great tutorial!

My question, is there any chance, that I can record a fixed area off the screen x- and y-Position with a fixed width and height?
Thx

Collapse
 
cooper4111 profile image
Cooper4111 • Edited

TL;DR: your solution generates broken files for chrome.

There's an issue with Chrome, that leads to losing metadata on video files created using MediaRecorder. The file is playable, yet, it has no duration so you can't scroll it and it's always 00:00 / 00:00. You've added
let video = document.querySelector("video")
video.src = url

Which is meaningless, unless you're trying to implement this workaround. But it requires changing the currentTime and doesn't actually work for saved file, only for <video> tag in document.

I'm not being toxic about your topic, just struggling myself to solve this. Any ideas are welcome.

Collapse
 
aminis profile image
Amin

Your script is just awesome. This script only record video. Can you please add audio option when recording screen.

Collapse
 
ryansmith94 profile image
Ryan Smith

Did you repost this to Medium?

javascript.plainenglish.io/lets-us...

Collapse
 
berriz44 profile image
berriz44-yt

Can I export the video in MP4 format?

Collapse
 
khairunnisaas profile image
Khairunnisaas

amazing tutorial!! but can we remove the share screen dialog before it start recording?

Collapse
 
pranavps020 profile image
pranavps020

Great Article mate , getDisplayMedia isn't supported in android& ios. Is thre any work around ?. All I'm looking for is to record a webpage as a video don't have to record out side browser like getDisplayMedia.

Collapse
 
andiduferense profile image
andiduferense • Edited

Why bother when you can use the usual programs like this and not bother. I just like such programs for their simplicity and convenience. Even a child can relax with them.

Collapse
 
sbkrish profile image
Balakrishnan Subramaniyan • Edited

This is a cool tutorial. Liked a lot.
Could you please include an Internal Audio record method with this?

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

Sure, You're most welcome

Collapse
 
yosi profile image
yosi

Great post. Thank you!

Collapse
 
0shuvo0 profile image
Shuvo

Glad you liked it

Collapse
 
mustafatoprakk profile image
mustafatoprakk

Thank you buddy. Ä°t's very beautiful

Collapse
 
0shuvo0 profile image
Shuvo

Many Thanks I am glad you liked it

Collapse
 
suhakim profile image
sadiul hakim

wow

Collapse
 
prabhukadode profile image
Prabhu

Nice

Collapse
 
0shuvo0 profile image
Shuvo

Thank you

Collapse
 
monfernape profile image
Usman Khalil

Very clear explanation. Loved it

Collapse
 
0shuvo0 profile image
Shuvo

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

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

Thanks a lot.
I also followed you back.