Electron Screen Capture Tutorial Build an Electron App that can capture and record video files from your desktop. 676 words. By Jeff Delaney Created Mar 4, 2020 Last Updated Mar 4, 2020 Code Slack #electron #javascript #node Electron opens the world of desktops apps to the average JavaScript developer. It wraps Chromium with Node.js, providing a browser for building UIs and Node for low-level system operations. The following project tutorial demonstrates how to build a simple screen recorder with Electron. The app can retrieve the available screens from the system, turn the screen into a video feed, then record and save the raw video file to the system. Initial Setup Electron Forge Create a new app with Electron Forge - it provides a solid starting point for building and distributing the app. command line npx create-electron-app my-app cd my-app npm start 💡 Tip - Enter rs into the terminal to restart the app after making code changes. HTML Markup The HTML contains a <video> element to preview the output from a screen and provides buttons to start/stop recording. file_type_html index.html <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Simple Screen Recorder</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.8.0/css/bulma.min.css" /> <link rel="stylesheet" href="index.css" /> <script defer src="render.js"></script> </head> <body class="content"> <h1>âš¡ Electron Screen Recorder</h1> <video></video> <button id="startBtn" class="button is-primary">Start</button> <button id="stopBtn" class="button is-warning">Stop</button> <hr /> <button id="videoSelectBtn" class="button is-text"> Choose a Video Source </button> </body> </html> Include Node in Electron’s Render Process In order to use Node in Electron’s frontend render process, we need to need to add the following config option: file_type_js_official index.js const mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { /// <-- update this option nodeIntegration: true } }); Screen Recorder Create a file named src/render.js. All code in this section runs in this file. Get Available Screens How do we access the available windows or screens to record? Electron has a built-in desktopCapturer that returns a list of the user’s screens. file_type_js_official render.js const videoSelectBtn = document.getElementById('videoSelectBtn'); videoSelectBtn.onclick = getVideoSources; const { desktopCapturer, remote } = require('electron'); const { Menu } = remote; // Get the available video sources async function getVideoSources() { const inputSources = await desktopCapturer.getSources({ types: ['window', 'screen'] }); } Display a Popup Menu At this point we have a list of screens, but need a UI element for the user to select one. This is a good use-case for a popup menu. const { desktopCapturer, remote } = require('electron'); const { Menu } = remote; async function getVideoSources() { const inputSources = await desktopCapturer.getSources({ types: ['window', 'screen'] }); const videoOptionsMenu = Menu.buildFromTemplate( inputSources.map(source => { return { label: source.name, click: () => selectSource(source) }; }) ); videoOptionsMenu.popup(); } Preview Video Stream Once a screen is selected it should be previewed in the video element. The code below uses navigator.mediaDevices.getUserMedia to turn the screen into a raw video feed. A MediaRecorder instance is created to record the stream as a webm video file that can be played back. let mediaRecorder; // MediaRecorder instance to capture footage const recordedChunks = []; // Change the videoSource window to record async function selectSource(source) { videoSelectBtn.innerText = source.name; const constraints = { audio: false, video: { mandatory: { chromeMediaSource: 'desktop', chromeMediaSourceId: source.id } } }; // Create a Stream const stream = await navigator.mediaDevices .getUserMedia(constraints); // Preview the source in a video element videoElement.srcObject = stream; videoElement.play(); // Create the Media Recorder const options = { mimeType: 'video/webm; codecs=vp9' }; mediaRecorder = new MediaRecorder(stream, options); // Register Event Handlers mediaRecorder.ondataavailable = handleDataAvailable; mediaRecorder.onstop = handleStop; } Record and Save a Video File The final step is to give the user control over the recording and saving of a video file. const { writeFile } = require('fs'); const { dialog, Menu } = remote; const startBtn = document.getElementById('startBtn'); startBtn.onclick = e => { mediaRecorder.start(); startBtn.classList.add('is-danger'); startBtn.innerText = 'Recording'; }; const stopBtn = document.getElementById('stopBtn'); stopBtn.onclick = e => { mediaRecorder.stop(); startBtn.classList.remove('is-danger'); startBtn.innerText = 'Start'; }; // Captures all recorded chunks function handleDataAvailable(e) { console.log('video data available'); recordedChunks.push(e.data); } // Saves the video file on stop async function handleStop(e) { const blob = new Blob(recordedChunks, { type: 'video/webm; codecs=vp9' }); const buffer = Buffer.from(await blob.arrayBuffer()); const { filePath } = await dialog.showSaveDialog({ buttonLabel: 'Save video', defaultPath: `vid-${Date.now()}.webm` }); console.log(filePath); writeFile(filePath, buffer, () => console.log('video saved successfully!')); }