Skip to content

Instantly share code, notes, and snippets.

@kishorek
Last active December 10, 2025 01:43
Show Gist options
  • Select an option

  • Save kishorek/4fb056e2ad931a1c65e971622d002136 to your computer and use it in GitHub Desktop.

Select an option

Save kishorek/4fb056e2ad931a1c65e971622d002136 to your computer and use it in GitHub Desktop.
Record Tab Bookmarklet
javascript:(function(){if(window.__tabRecActive){alert('Tab Recorder is already running.');return;}window.__tabRecActive=true;var css='#tab-rec-ui{position:fixed;top:12px;right:12px;z-index:2147483647;background:rgba(17,17,17,.92);color:#fff;padding:10px 12px;border-radius:10px;font:13px/1.4 system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;box-shadow:0 6px 18px rgba(0,0,0,.35)}#tab-rec-ui button{background:#1f6feb;border:0;color:#fff;padding:6px 10px;border-radius:6px;cursor:pointer}#tab-rec-ui button[disabled]{opacity:.55;cursor:not-allowed}#tab-rec-ui .row{margin-top:6px}#tab-rec-ui .muted{opacity:.8;font-size:12px}';var style=document.createElement('style');style.textContent=css;document.head.appendChild(style);var ui=document.createElement('div');ui.id='tab-rec-ui';ui.innerHTML='<div style="font-weight:600;margin-bottom:6px">Tab Recorder</div><div class="row"><button id="tr-start">Start</button> <button id="tr-pause" disabled>Pause</button> <button id="tr-stop" disabled>Stop</button></div><div id="tr-time" class="row muted">00:00</div><div class="row muted">Hotkeys: Alt+Shift+P pause/resume, Alt+Shift+S stop</div><label class="row" style="display:flex;align-items:center;gap:8px"><input id="tr-mic" type="checkbox"> Include microphone</label>';document.body.appendChild(ui);var $=function(s){return ui.querySelector(s)};var btnStart=$('#tr-start'),btnPause=$('#tr-pause'),btnStop=$('#tr-stop'),cbMic=$('#tr-mic'),lblTime=$('#tr-time');var displayStream=null,micStream=null,mixedStream=null,recorder=null,chunks=[],timer=null,startTs=0,paused=false,mime='';function setTime(ms){var s=Math.floor(ms/1000);var m=('0'+Math.floor(s/60)).slice(-2);var ss=('0'+(s%60)).slice(-2);lblTime.textContent=m+':'+ss;}function clearAll(){try{if(timer)clearInterval(timer);}catch(e){}[displayStream,micStream,mixedStream].forEach(function(st){if(st){st.getTracks().forEach(function(tr){try{tr.stop()}catch(e){}});}});if(ui&&ui.parentNode)ui.parentNode.removeChild(ui);if(style&&style.parentNode)style.parentNode.removeChild(style);window.__tabRecActive=false;}function chooseMime(){if(window.MediaRecorder&&MediaRecorder.isTypeSupported){if(MediaRecorder.isTypeSupported('video/webm;codecs=vp9,opus'))return 'video/webm;codecs=vp9,opus';if(MediaRecorder.isTypeSupported('video/webm;codecs=vp8,opus'))return 'video/webm;codecs=vp8,opus';}return '';}function start(){btnStart.disabled=true;cbMic.disabled=true;navigator.mediaDevices.getDisplayMedia({video:{frameRate:30},audio:true}).then(function(ds){displayStream=ds;var includeMic=cbMic.checked;var streamForRecorder=displayStream;var next=Promise.resolve();if(includeMic){next=next.then(function(){return navigator.mediaDevices.getUserMedia({audio:{echoCancellation:true,noiseSuppression:true,autoGainControl:true}});}).then(function(ms){micStream=ms;var ctx=new (window.AudioContext||window.webkitAudioContext)();var dest=ctx.createMediaStreamDestination();try{if(displayStream.getAudioTracks().length>0){var sysSrc=ctx.createMediaStreamSource(displayStream);sysSrc.connect(dest);}var micSrc=ctx.createMediaStreamSource(micStream);micSrc.connect(dest);}catch(e){}mixedStream=new MediaStream(displayStream.getVideoTracks().concat(dest.stream.getAudioTracks()));streamForRecorder=mixedStream;}).catch(function(e){alert('Microphone permission denied. Continuing without mic.');});}return next.then(function(){mime=chooseMime();var opts=mime?{mimeType:mime,videoBitsPerSecond:5000000,audioBitsPerSecond:128000}:{videoBitsPerSecond:5000000,audioBitsPerSecond:128000};recorder=new MediaRecorder(streamForRecorder,opts);chunks=[];recorder.ondataavailable=function(e){if(e.data&&e.data.size>0)chunks.push(e.data);};recorder.onstop=function(){try{var blob=new Blob(chunks,{type:mime||'video/webm'});var url=URL.createObjectURL(blob);var a=document.createElement('a');var ts=new Date().toISOString().replace(/[:.]/g,'-');a.href=url;a.download=(document.title||'Tab')+'-'+ts+'.webm';document.body.appendChild(a);a.click();setTimeout(function(){URL.revokeObjectURL(url);a.remove();},1000);}catch(e){}clearAll();};var vTrack=displayStream.getVideoTracks()[0];if(vTrack){vTrack.addEventListener('ended',function(){try{if(recorder&&recorder.state!=='inactive')recorder.stop();}catch(e){}},{once:true});}recorder.start(1000);startTs=Date.now();setTime(0);timer=setInterval(function(){if(!paused)setTime(Date.now()-startTs);},500);btnPause.disabled=false;btnStop.disabled=false;});}).catch(function(e){alert('Screen/tab capture was cancelled.');clearAll();});}function pauseResume(){if(!recorder)return;try{if(recorder.state==='recording'){recorder.pause();paused=true;btnPause.textContent='Resume';}else if(recorder.state==='paused'){recorder.resume();paused=false;btnPause.textContent='Pause';}}catch(e){}}function stop(){try{btnPause.disabled=true;btnStop.disabled=true;if(recorder&&recorder.state!=='inactive')recorder.stop();}catch(e){clearAll();}}btnStart.addEventListener('click',start);btnPause.addEventListener('click',pauseResume);btnStop.addEventListener('click',stop);window.addEventListener('keydown',function(e){if(e.altKey&&e.shiftKey&&e.code==='KeyS'){e.preventDefault();stop();}else if(e.altKey&&e.shiftKey&&e.code==='KeyP'){e.preventDefault();pauseResume();}});})();
javascript:(function(){ var SRC='https://gist.githubusercontent.com/kishorek/4fb056e2ad931a1c65e971622d002136/raw/77ca34634cb65aa48159b60852faac22d2dfc67b/record.js'; fetch(SRC,{mode:'cors',cache:'no-store',credentials:'omit'}) .then(function(r){ if(!r.ok) throw new Error('HTTP '+r.status); return r.text(); }) .then(function(code){ var blob=new Blob([code],{type:'text/javascript'}); var url=URL.createObjectURL(blob); var s=document.createElement('script'); s.src=url; document.documentElement.appendChild(s); s.onload=function(){ URL.revokeObjectURL(url); s.remove(); }; }) .catch(function(e){ alert('Failed to load recorder: '+e.message); }); })();
javascript:(function(){if(window.tr){alert('Tab Recorder is already running.');return;}window.tr=1;var r,ch=[],m='';navigator.mediaDevices.getDisplayMedia({video:{frameRate:30},audio:true}).then(function(s){function done(){try{var b=new Blob(ch,{type:m||'video/webm'});var u=URL.createObjectURL(b);var a=document.createElement('a');var ts=new Date().toISOString().replace(/[:.]/g,'-');a.href=u;a.download=(document.title||'Tab')+'-'+ts+'.webm';document.body.appendChild(a);a.click();setTimeout(function(){URL.revokeObjectURL(u);a.remove()},1000);}catch(e){}try{s.getTracks().forEach(function(t){t.stop()});}catch(e){}window.tr=0;}try{m=MediaRecorder.isTypeSupported('video/webm;codecs=vp9,opus')?%27video/webm;codecs=vp9,opus%27:(MediaRecorder.isTypeSupported(%27video/webm;codecs=vp8,opus%27)?%27video/webm;codecs=vp8,opus%27:%27%27);}catch(e){}try{r=new MediaRecorder(s,m?{mimeType:m}:{})}catch(e){r=new MediaRecorder(s)}r.ondataavailable=function(e){if(e.data&&e.data.size)ch.push(e.data)};var v=s.getVideoTracks()[0];if(v){v.addEventListener(%27ended%27,function(){try{if(r&&r.state!==%27inactive%27)r.stop()}catch(e){done()}},{once:true})}r.onstop=done;r.start(1000);window.addEventListener(%27keydown%27,function(e){if(e.altKey&&e.shiftKey&&e.code===%27KeyS%27){e.preventDefault();try{r.stop()}catch(e){done()}}},{once:true});alert(%27Recording started. Press Alt+Shift+S to stop.%27);}).catch(function(){window.tr=0;alert(%27Screen/tab capture was cancelled.%27);});})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment