Record Your Webcam with HTML5 and Javascript

Posted by Gal Ratner on 10/18/2021

If you ever wanted to record your webcam without any special plug in or software, HTML5 has MediaRecorder built in functionality.

Its pretty simple:

First you need to request access to the the user's camera and microphone:


navigator.mediaDevices.getUserMedia({ audio: true, video: true }).then(startPreview);


Then set a preview stream to your own video element:

player.srcObject = stream;

and start a MediaRecorder with the same stream using your desired encoding - as long as your browser supports it:

if (MediaRecorder.isTypeSupported('video/webm;codecs=vp9')) {
			options = { mimeType: 'video/webm; codecs=vp9' };
		} else if (MediaRecorder.isTypeSupported('video/webm;codecs=vp8')) {
			options = { mimeType: 'video/webm; codecs=vp8' };
		} else {
			options = { mimeType: 'video/webm' };
		}
 
		const mediaRecorder = new MediaRecorder(stream, options);

Both Chrome and Firefox support different encodings, so depending on your selected encoding you might need to save your file with different extensions.

The MediaRecorder pushes its data into an array:

mediaRecorder.addEventListener('dataavailable', function (e) {
			if (e.data.size > 0) {
				recordedChunks.push(e.data);
			}
		});

In order to download the file you will then need to convert the array into a blob media file:

downloadLink.href = URL.createObjectURL(new Blob(recordedChunks));
downloadLink.download = 'video.webm';

Complete example including a playback is below:


<video id="player" controls autoplay muted height="400" width="400"></video>
<video id="playbackPlayer" controls autoplay height="400" width="400"></video>
<br />
<button id="start">Start</button>
<button id="stop">Stop</button>
<button id="playback">Playback</button>
<button id="clear">Start Over</button>
<button id="send">Send</button>
<br />
<div id="counter">20 second message</div>
<br />
<a id="download">Download</a>
 
 
<script>
	// Todo: add a counter and only allow them 15 seconds.
	// After that stop the recording.
	const maxSeconds = 20;
	var recordingSeconds = 0;
	var stopCounter = false;
	var player = document.getElementById('player');
	var playbackPlayer = document.getElementById('playbackPlayer');
	let stopped = true;
	let recordedChunks = [];
	
	const startButton = document.getElementById('start');
	const stopButton = document.getElementById('stop');
	const playbackButton = document.getElementById('playback');
	const clearButton = document.getElementById('clear');
	const sendButton = document.getElementById('send');
	const downloadLink = document.getElementById('download');
 
	
	var startPreview = function (stream) {
		player.srcObject = stream;
		startButton.disabled = false;
		stopButton.disabled = true;
		playbackButton.disabled = true;
		clearButton.disabled = true;
		
		initRecorder(stream);
	};
 
	var initRecorder = function (stream) {
		var options;
		if (MediaRecorder.isTypeSupported('video/webm;codecs=vp9')) {
			options = { mimeType: 'video/webm; codecs=vp9' };
		} else if (MediaRecorder.isTypeSupported('video/webm;codecs=vp8')) {
			options = { mimeType: 'video/webm; codecs=vp8' };
		} else {
			options = { mimeType: 'video/webm' };
		}
 
		const mediaRecorder = new MediaRecorder(stream, options);
 
		mediaRecorder.addEventListener('dataavailable', function (e) {
			if (e.data.size > 0) {
				recordedChunks.push(e.data);
			}
		});
 
		mediaRecorder.addEventListener('stop', function () {
			startButton.disabled = false;
			stopButton.disabled = true;
			clearButton.disabled = false;
			if (recordedChunks.length > 0) {
				playbackButton.disabled = false;
			}
			downloadLink.href = URL.createObjectURL(new Blob(recordedChunks));
			downloadLink.download = 'video.webm';
		});
 
		mediaRecorder.addEventListener('start', function () {
			startButton.disabled = true;
			stopButton.disabled = false;
			clearButton.disabled = true;
			playbackButton.disabled = true;
			recordingSeconds = 0;
			stopCounter = false;
			recordedChunks = [];
			var x = setInterval(function () {
				if (stopCounter) {
					clearInterval(x);
				}
				if (recordingSeconds <= maxSeconds) {
					document.getElementById("counter").innerHTML = (maxSeconds - recordingSeconds) + " seconds left...";
					recordingSeconds++;
				} else {
					if (mediaRecorder.state === "recording") {
						mediaRecorder.stop();
					}
					document.getElementById("counter").innerHTML = "Thank you! Press send to send to the couple.";
					clearInterval(x);
				}
			}, 1000)
		});
 
		startButton.addEventListener('click', function () {
			if (mediaRecorder.state === "inactive") {
				mediaRecorder.start();
			}
		});
 
		stopButton.addEventListener('click', function () {
			if (mediaRecorder.state === "recording") {
				mediaRecorder.stop();
				stopCounter = true;
			}
		});
 
		playbackButton.addEventListener('click', function () {
			if (mediaRecorder.state === "recording") {
				mediaRecorder.stop();
			}
 
			if (recordedChunks.length > 0) {
				playbackPlayer.src = URL.createObjectURL(new Blob(recordedChunks));
				playbackPlayer.start();
			}
		});
 
		clearButton.addEventListener('click', function () {
			if (mediaRecorder.state === "recording") {
				mediaRecorder.stop();
			}
			
			setTimeout(function () {
				recordedChunks = [];
				alert("Video Deleted. You many start recording.");
			}, 2000);
		});
 
		sendButton.addEventListener('click', function () {
			alert("Push the data to a backend service.");
			
		});
	};
 
	navigator.mediaDevices.getUserMedia({ audio: true, video: true }).then(startPreview);
 
</script>

Did you find this useful?

Please visit my Software Consulting firm Inverted Software


No Comments Yet. Join The Conversation