diff --git a/frontend/app/components/Session_/ScreenRecorder/ScreenRecorder.tsx b/frontend/app/components/Session_/ScreenRecorder/ScreenRecorder.tsx
new file mode 100644
index 000000000..9f8d239fb
--- /dev/null
+++ b/frontend/app/components/Session_/ScreenRecorder/ScreenRecorder.tsx
@@ -0,0 +1,56 @@
+import React from 'react';
+import { screenRecorder } from 'App/utils/screenRecorder';
+import { Tooltip } from 'react-tippy'
+
+let stopRecorderCb: () => void
+
+/**
+ * "edge" || "edg/" chromium based edge (dev or canary)
+ * "chrome" && window.chrome chrome
+ * "opr" && (!!window.opr || !!window.opera) opera
+ * "trident" ie
+ * "firefox" firefox
+ * "safari" safari
+ */
+function isSupported() {
+ const agent = window.navigator.userAgent.toLowerCase()
+
+ if (agent.includes("edge") || agent.includes("edg/")) return true
+ // @ts-ignore
+ if (agent.includes("chrome") && !!window.chrome) return true
+
+ return false
+}
+
+function ScreenRecorder() {
+ const [isRecording, setRecording] = React.useState(false);
+
+ const toggleRecording = async () => {
+ console.log(isRecording);
+ if (isRecording) {
+ stopRecorderCb?.();
+ setRecording(false);
+ } else {
+ const stop = await screenRecorder();
+ stopRecorderCb = stop;
+ setRecording(true);
+ }
+ };
+
+ const isSupportedBrowser = isSupported()
+ if (!isSupportedBrowser) return (
+
+ {/* @ts-ignore */}
+
+ Record
+
+
+ )
+ return (
+
+
{isRecording ? 'STOP' : 'RECORD'}
+
+ );
+}
+
+export default ScreenRecorder
diff --git a/frontend/app/utils.ts b/frontend/app/utils/index.ts
similarity index 100%
rename from frontend/app/utils.ts
rename to frontend/app/utils/index.ts
diff --git a/frontend/app/utils/screenRecorder.ts b/frontend/app/utils/screenRecorder.ts
new file mode 100644
index 000000000..47acf6bca
--- /dev/null
+++ b/frontend/app/utils/screenRecorder.ts
@@ -0,0 +1,91 @@
+const FILE_TYPE = 'video/webm';
+const FRAME_RATE = 30;
+
+function createFileRecorder (stream: MediaStream, mimeType: string) {
+ let ended = false;
+ let recordedChunks: BlobPart[] = [];
+ const SAVE_INTERVAL_MS = 200;
+ const mediaRecorder = new MediaRecorder(stream);
+
+ mediaRecorder.ondataavailable = function (e) {
+ if (e.data.size > 0) {
+ recordedChunks.push(e.data);
+ }
+ };
+
+ function onEnd() {
+ if (ended) return;
+
+ ended = true;
+ saveFile(recordedChunks, mimeType);
+ recordedChunks = [];
+ };
+
+ // sometimes we get race condition or the onstop won't trigger at all,
+ // this is why we have to make it twice to make sure that stream is saved
+ // plus we want to be able to handle both, native and custom button clicks
+ mediaRecorder.stream.getTracks().forEach(track => track.onended = onEnd);
+ mediaRecorder.onstop = () => {
+ onEnd();
+ mediaRecorder.stream.getTracks().forEach(track => track.stop());
+ }
+ mediaRecorder.start(SAVE_INTERVAL_MS);
+
+ return mediaRecorder;
+}
+
+function saveFile(recordedChunks: BlobPart[], mimeType: string) {
+ const blob = new Blob(recordedChunks, {
+ type: mimeType,
+ });
+ const filename = +new Date() + '.' + mimeType.split('/')[1];
+ const downloadLink = document.createElement('a');
+ downloadLink.href = URL.createObjectURL(blob);
+ downloadLink.download = filename;
+
+ document.body.appendChild(downloadLink);
+ downloadLink.click();
+
+ URL.revokeObjectURL(downloadLink.href); // clear from memory
+ document.body.removeChild(downloadLink);
+}
+
+async function recordScreen() {
+ return await navigator.mediaDevices.getDisplayMedia({
+ audio: true,
+ video: { frameRate: FRAME_RATE },
+ // potential chrome hack
+ // @ts-ignore
+ preferCurrentTab: true,
+ });
+};
+
+/**
+* Creates a screen recorder that sends the media stream to MediaRecorder
+* which then saves the stream to a file.
+*
+* Supported Browsers:
+*
+* Windows: Chrome v91+, Edge v90+ - FULL SUPPORT;
+* *Nix: Chrome v91+, Edge v90+ - LIMITED SUPPORT - (audio only captured from current tab)
+*
+* @returns a promise that resolves to a function that stops the recording
+*/
+export async function screenRecorder() {
+ try {
+ const stream = await recordScreen();
+ const mediaRecorder = createFileRecorder(stream, FILE_TYPE);
+
+ return () => mediaRecorder.stop();
+ } catch (e) {
+ console.log(e)
+ }
+}
+
+// @ts-ignore
+window.recordSceenSample = screenRecorder;
+
+// NOT SUPPORTED:
+// macOS: chrome and edge only support capturing current tab's audio
+// windows: chrome and edge supports all audio
+// other: not supported