loading...
Cover image for Screen Recording in 10 lines of Vanilla JS

Screen Recording in 10 lines of Vanilla JS

sebastianstamm profile image Sebastian Stamm ・3 min read

Let’s have a look at how we can capture and record your users screen. Not just your page, but also other tabs of the users browser, the desktop and even other applications. And we will do that without browser plugins or huge libraries. Instead, we just need 10 lines of Vanilla Javascript.

To achieve this, we will use the Media Capture and Streams API. It’s related to the WebRTC API, but for now we ignore all the peer-to-peer streaming between browsers and just do very bare-bones recording.

Full Example

While we could send the recording to a server to store or process it, for this blog post we just capture it and then play it back to the user in a <video> tag. You can find the complete example here: https://codesandbox.io/s/sharp-mestorf-qumzf.

To try it out, click the "Start Recording" button, select which screen you want to share, perform some actions and then click the "Stop Recording" button.

You might notice that the example contains more than 10 lines of Javascript. This is because it also contains a bit more code to deal with the start and stop buttons. The recording logic can be found in the startRecording function, starting from line 6. In summary, this function performs these three steps:

  1. Create a video stream of the users desktop
  2. Record this stream
  3. Convert the recording to transmit it to the server or show it in the <video> tag

Let’s look at each step in detail:

Create a Video Stream

const stream = await navigator.mediaDevices.getDisplayMedia({
  video: { mediaSource: "screen" }
});

It’s just a single function: getDisplayMedia. Calling this opens a dialog for the user to choose which screen to record from (if they have multiple displays). They can also choose to just record a specific application or browser tab. Two things to keep in mind here: The user has to actively allow the sharing, so you cannot use this feature to spy on your users. Also, it returns a promise, so make sure to await it.

Record the Stream

const recorder = new MediaRecorder(stream);

const chunks = [];
recorder.ondataavailable = e => chunks.push(e.data);
recorder.start();

Here, we use the MediaRecorder API to capture the stream we got from the previous step. Since video streams can get quite big, the recorder can periodically call ondataavailable. For now, we store each video chunk in an array and will deal with it in the next step. After setting up the data handling, we start the recording.

Convert the Recording to a Blob

recorder.onstop = e => {
  const completeBlob = new Blob(chunks, { type: chunks[0].type });
  video.src = URL.createObjectURL(completeBlob);
};

At some point, we need to call recorder.stop(); In the example, this happens when you click the "Stop Recording" button. This will call the onstop event handler of the recorder. There we take the chunks from the previous step and convert them into a Blob. And then you can do whatever with it.

You could send it to your server as part of your "Submit Feedback" functionality. You could upload it to Youtube. Here, we just play the recording back to the user by constructing an object url and using it as src attribute for the video tag.


And there we have it, with just 10 lines of Javascript (plus a little bit more for the recording controls), we were able to capture the users screen. I trust you to use this power for good, not evil.

Posted on by:

sebastianstamm profile

Sebastian Stamm

@sebastianstamm

Software Engineer, Tech Speaker, Author, Artist who loves building both complex software systems as well as quick tech prototypes.

Discussion

pic
Editor guide
 

This is great !
But the method getDisplayMedia can fail. You can see this by wrapping the async call in a try catch bloc and catching the error.
And that's a good thing, it's pretty obvious why this method should be protected. I don't know about Windows, but under Mac you must give it access to your browser from the system and not only the browser. Besides, this method cannot be called programmatically :
Only the user can call it from an html button.

Still a great article ! It's a fantastic tool to play with.

 

// , Whoa. If your 10 lines of Javascript could record my face right now, it'd look like I've seen a ghost.

I will definitely use this for evil.

The potential for bug reporting, at the very least, is huge.

This is going out to anyone who works on frontend stuff in our company and affiliates.

 

Well, recording your face with these 10 lines is also possible, just replace the getDisplayMedia call with getUserMedia({video: true})

The initial work at my company that lead to this article was also related to bug recording. Together with some event listeners that capture all keyboard and mouse interactions you can build quite powerful tools. Still, for screen and webcam recordings you need active user consent, which makes it harder to abuse.

 

Hello,
I am looking for a way to record an svg animation in a div assign it to a blob and set a video src to the blob's url then download this animation as an mp4 format.
Do you think this could work and if so how do I approach it
Thanks

 

Hey - great tutorial! Quick question - is it possible to select just a portion of the screen to record?

 

Depending on the browser, you can select to record the whole screen, just a single application window, or a specific tab. If you need an even more specific portion - e.g. only a section of a specific tab - you could do that in post-processing:

Record the whole tab (or window or screen) and then modify the resulting video so that only the desired portion remains. This "modify the resulting video" is probably quite complicated though. If you find a nice Javascript library for video editing, please let me know!

 

Gotcha, thanks!

 

Very nice hehe.. Is there a way I can record the window and stream it in real time?

 

Sure! Instead of pushing the data into an array in the ondataavailable handler, you could also send it to a server or connected peers. For real-time, you probably want to specify the timeslice argument when starting the recording, like recorder.start(100); to make sure you data handler is called periodically instead of at the end

 

but how do you pass it to the server ?
in the form of a blob or something else?
cause i wanted to emit it using socket.io

 

Sebastian, Is there a way to also record the audio from the microphone?

 

Sure! Instead of calling getDisplayMedia you would need to call getUserMedia, like this:

const stream = await navigator.mediaDevices.getUserMedia({
  audio: true
});

You can then plug this stream into the MediaRecorder like described in the post.

 

Is there a way to record a tab/window/specific site without user permissions?

 

Not in a video stream. The closest thing you could do is periodically get a snapshot of the current DOM with something like document.body.innerHTML and send it to your server. You could then reconstruct the site based on this HTML.

If you want mouse cursor positions too, you would need a global mousemove handler that tracks the cursor position and also send it to your server.

Of course this only works on your own page. Recording another tab or even window this way without the users consent is fortunately not possible :)

 

how can we implement live stream to server from client using this same.

 

pls write a post on using this for live streaming with socket.io