Html5 Screen Recording Utility For PC

WebRec

Add PC screen recording to your website — capture the full desktop, a window, or a tab, plus microphone and webcam. Floating controls, recovery, and self-contained docs. Works in the browser on the user’s computer (no desktop app). Developers: API global is WebRec.

Checking support…

Getting started (non-technical)

You do not need Node.js or a build tool to try WebRec. Follow these steps on your computer:

  1. Unzip the download. You should see folders like assets/sdk/, assets/libraries/, examples/, and files such as index.html.
  2. Open the folder with a local web server (Laragon, XAMPP, VS Code Live Server, or npx serve). Browsers block screen recording on plain file:// pages.
  3. Visit Studio (index.html) over http://localhost or HTTPS.
  4. Click Record, choose Screen / Window / Tab in the browser picker, then use Pause / Stop when finished.
  5. Use Download WebM to save the original file, or Download MP4 to convert and save an MP4.
License tip: Core recording is included with your purchase. Bundled libraries (Bootstrap, fonts, lightGallery, FFmpeg.wasm for Studio MP4) are free & open-source — see CREDITS.md.

Recording workflow

How a typical session moves from click to saved video:

Flowchart: Start, browser share picker, recording with optional pause, stop, then preview download or share
Figure: Start → browser share picker → record (optional pause) → stop → preview / download / share. (Asset: docs/images/workflow-diagram.svg — included in the download package.)
  1. Start — your page calls recorder.start() (or the user clicks Record in Studio).
  2. Share picker — the browser asks the user what to share (screen, window, or tab).
  3. Countdown (optional) — if countdown > 0, wait after the picker; with float / Document PiP enabled the digits appear on the float bar, not on the page being recorded.
  4. Record — MediaRecorder writes chunks; floating controls stay available.
  5. Stop — a Blob + object URL are returned on the stop event.
  6. Deliver — Download WebM, Download MP4, Web Share, upload hook, or your own storage.

Studio & floating toolbar tour

Studio (index.html) is the flagship demo. The floating toolbar appears while a capture is active.

Annotated Studio interface highlighting preview, transport controls, and tools panel
Studio: preview canvas, transport (Record / Pause / Stop), and the Tools panel (Download WebM, Download MP4, share, frames).
Annotated floating toolbar with pause, stop, screenshot, and timer labels
Floating toolbar: timer, pause/resume, stop, screenshot, and optional webcam PiP.
  • Quality → Container — Studio defaults to WebM (most reliable in Chrome). You can ask for MP4 while recording when the browser supports it.
  • Capture → Start after — optional countdown after the share picker. With Float bar on, the timer shows in the floating controls (outside the captured tab/window), so it is not baked into the recording or thumbnails. Screenshots are disabled until recording starts.
  • Tools → Download WebM — saves the original recording as-is.
  • Tools → Download MP4 — converts WebM → MP4 in the browser using bundled FFmpeg.wasm (see assets/libraries/ffmpeg/core/README.md). First click may take a few seconds while the converter loads.

Tip: open Studio, start a short recording, and capture your own screenshots for marketing — see ../seller/SCREENSHOTS.md for Envato size rules.

Download & MP4 convert

Most browsers record WebM. Many buyers want an MP4 file for sharing and editing. Studio makes that a one-click step after you stop:

  1. Record (WebM by default).
  2. Click Download MP4.
  3. Wait for convert (progress shows on the button), then the .mp4 downloads.

Converter files are self-hosted under assets/libraries/ffmpeg/ (no CDN). Studio loads them via assets/js/convert-to-mp4.js only when you click Download MP4.

// Same idea in your own page (ES module):
import { convertBlobToMp4 } from './assets/js/convert-to-mp4.js';

recorder.on('stop', async ({ blob }) => {
  const mp4 = await convertBlobToMp4(blob);
  WebRec.downloadBlob(mp4, 'recording.mp4');
});

Plugin API (optional): WebRec.FFmpegConvert({ coreURL, wasmURL }) adds recorder.convert() — point paths at assets/libraries/ffmpeg/core/ffmpeg-core.js and .wasm. See example 32 and CREDITS.md.

Quick start (code)

Serve over HTTPS or localhost, then:

<link rel="stylesheet" href="assets/sdk/webrec.css">
<script src="assets/sdk/webrec.umd.js"></script>
<script>
  const recorder = new WebRec.ScreenCapture({ theme: 'light' });
  recorder.on('stop', ({ blob, url }) => console.log(blob));
  recorder.start();
</script>

Installation

  1. Copy assets/sdk/ into your project (and assets/libraries/ only if you want Studio/docs styling assets such as Bootstrap).
  2. Include CSS + UMD (or ESM) on an HTTPS / localhost page — no CDN and no Node.js build step.
  3. Create new WebRec.ScreenCapture(), call start(), listen for stop.
  4. Call destroy() when your page or component unmounts.
  • ESM: import ScreenCapture from './assets/sdk/webrec.esm.js'
  • Types: assets/sdk/webrec.d.ts
  • Try everything: open Studio (index.html)

Use cases & guidelines

WebRec records what the user shares via the browser picker (getDisplayMedia) and writes a client-side Blob with MediaRecorder. It is not a Zoom replacement, not a hosted cloud recorder, and not a native mobile SDK. Serve over HTTPS or localhost.

Naming (UMD vs ESM)

  • UMD: new WebRec.ScreenCapture({…}) — helpers like WebRec.downloadBlob, WebRec.ChunkUploader.
  • ESM: import ScreenCapture from './assets/sdk/webrec.esm.js' then new ScreenCapture({…}); named exports match the UMD API.

Recipe matrix

GoalRecommended setupExamples
Tutoring / courses (face + screen) Mic on; webcam PiP; set camera.includeInRecording: true when the face should appear in the export; persistChunks: true 02, 03, 15
Support / bug report preferCurrentTab: true or displaySurface: 'browser'; mic on; optional ChunkUploader or download 24, 16, 25
SaaS in-app recorder ui: false + your chrome; controlsPiP: true when capturing another window; always destroy() on unmount 10, 33, 30, 27
LMS / marketing clips Quality + MIME fallback; ThumbnailPlugin; Studio Download MP4 (bundled FFmpeg) or FFmpegConvert 04, 12, 14, 32
Long / crash-prone sessions persistChunks: true, smaller timeslice (e.g. 500), recover UI on page load 15
Privacy-minded capture excludeMonitorSurfaces: true; prefer tab; tell users they control the share picker 24 + Options
Accessible UI Keep shortcuts: true; don’t rely on float bar alone 08, 29

Decision guidelines

  • Tab vs window vs entire screen — the user chooses in the picker. Entire Screen can include your float popup; Document PiP stays on top but may not appear in the recording the same way.
  • Slim float vs Keep on top — default slim popup is predictable sizing; Document PiP (toolbar.preferDocumentPiP: true) is for agents who Alt-Tab and still need controls (Chrome/Edge).
  • Webcam overlay vs burn-in — PiP bubble is preview/UI; set includeInRecording: true only when the camera should be composited into the exported video.
  • Download vs share vs upload vs recovery — local download() needs no server; Studio Download MP4 converts WebM→MP4 in-browser; share() uses the browser Web Share sheet when available; ChunkUploader streams chunks to your API; IndexedDB recovers crashes without a server.
  • Bundled libraries & peers — lightGallery + FFmpeg.wasm (for Studio MP4) ship under assets/libraries/. WaveSurfer remains optional/not required. All free & open-source — see CREDITS.md.
  • Frameworks — create the recorder in mount, call destroy() on unmount (see example 30). Multiple instances are supported (example 28).

What users can / cannot record

Browsers may block or limit protected content (some DRM video, other apps’ audio, OS surfaces). Always handle PERMISSION_DENIED / cancel gracefully. Chrome/Edge offer the best system-audio + Document PiP support — see Browser support.

Core API

const recorder = new WebRec.ScreenCapture({
  ui: 'vanilla',           // 'vanilla' | 'bootstrap' | false
  theme: 'light',
  video: { frameRate: 30, width: 1920, height: 1080, bitrate: 2500000 },
  audio: { microphone: true, systemAudio: true, bitrate: 128000 },
  camera: { enabled: false, mirrored: true, includeInRecording: false },
  mimeType: 'video/webm;codecs=vp9,opus', // preferred; SDK falls back automatically (MP4 also supported)
  timeslice: 1000,         // MediaRecorder chunk interval (ms)
  persistChunks: true,     // IndexedDB crash recovery
  shortcuts: true,
  preferCurrentTab: false,
  displaySurface: undefined, // 'monitor' | 'window' | 'browser' (hint)
  excludeMonitorSurfaces: false,
  controlsPiP: false,
  countdown: 0,            // seconds after share picker before capture starts (0 = immediate)
  toolbar: { preferDocumentPiP: false },
  previewOnStop: true
});

await recorder.start();
recorder.pause();
recorder.resume();
await recorder.stop();
recorder.cancel();
await recorder.restart();
await recorder.screenshot();
await recorder.extractFrames({ fps: 1, maxFrames: 24 });
recorder.openFrameGallery(0);
recorder.openScreenshotGallery(0);
await recorder.openControlsPiP();
recorder.closeControlsPiP();
recorder.download('take.webm');
await recorder.share({ title: 'My recording' }); // Web Share when available
recorder.destroy();

WebRec.ScreenCapture.isSupported();
WebRec.ScreenCapture.getCapabilities();
WebRec.ScreenCapture.checkMimeType('video/webm;codecs=vp9,opus');

Full reference: API reference · Studio · Examples

Options (video, audio, camera, surface)

Pass options to the constructor or setOptions() / start(override).

  • videoframeRate, width, height, bitrate (bits/sec for MediaRecorder).
  • audiomicrophone, systemAudio, deviceId, echoCancellation, noiseSuppression, bitrate.
  • cameraenabled, width/height, deviceId, mirrored, includeInRecording (composite webcam into the recorded video when true).
  • mimeType — preferred container/codecs; use checkMimeType() first. Omit to let the SDK pick a supported fallback.
  • countdown — seconds to wait after the share picker before MediaRecorder starts (0 = immediate). Studio: Capture → Start after. With float controls / Document PiP, the countdown UI is shown on the float bar (outside tab/window capture) so it is not recorded; screenshots are blocked until recording starts.
  • timeslice — chunk size in ms for dataavailable / IndexedDB / upload plugins (e.g. 1000).
  • preferCurrentTab — Chrome hint to preselect the current tab in the share picker.
  • displaySurface — hint: 'monitor', 'window', or 'browser'.
  • excludeMonitorSurfaces — hide Entire Screen in the picker (when the browser supports it).
// Prefer recording this tab only (Chrome)
const tabRec = new WebRec.ScreenCapture({
  preferCurrentTab: true,
  audio: { systemAudio: true, microphone: false }
});

// Webcam PiP overlay + optional burn-in
const camRec = new WebRec.ScreenCapture({
  camera: {
    enabled: true,
    mirrored: true,
    width: 320,
    height: 240,
    includeInRecording: true
  }
});

// Force a MIME when supported
const checked = WebRec.ScreenCapture.checkMimeType('video/webm;codecs=vp9,opus');
const hiBitrate = new WebRec.ScreenCapture({
  mimeType: checked.mimeType,
  video: { frameRate: 30, bitrate: 5000000 },
  timeslice: 500
});

Demos: 24-prefer-current-tab, 12-mime-fallback, 03-webcam-pip

Floating controls

Set controlsPiP: true to open a floating toolbar when recording starts (or call openControlsPiP()).

  • Default — slim popup: window is sized to the toolbar strip. Included in Entire Screen recordings. May go behind other apps when you Alt-Tab.
  • Keep on top — Document PiP: set toolbar.preferDocumentPiP: true (Chrome/Edge). Stays above other windows. Chrome may reopen a tall remembered size; click Click to make slim on the PiP if needed.
const recorder = new WebRec.ScreenCapture({
  ui: false,
  controlsPiP: true,
  toolbar: { preferDocumentPiP: false }, // slim by default
  excludeMonitorSurfaces: false          // allow Entire Screen so controls can appear in the video
});

Demo: examples/33-controls-picture-in-picture.html

Frames, screenshots & gallery

After stop(), sample frames from the recording; during capture, take live screenshots of the display stream (useful while recording another window via the Float bar camera or Alt+S). Both open in a lightGallery lightbox, bundled and self-hosted under its free, open-source GPLv3 license — no extra commercial license required.

1) The gallery library is already bundled and self-hosted. After extract / screenshot:

recorder.openFrameGallery(0);
// or recorder.openScreenshotGallery(0);

2) Record, then open the galleries:

const recorder = new WebRec.ScreenCapture({
  theme: 'dark',
  audio: { microphone: true, systemAudio: true }
});

// Live screenshots while recording (display stream)
recorder.on('start', async () => {
  // Float bar camera / Alt+S also call screenshot()
  // await recorder.screenshot();
});

recorder.on('stop', async () => {
  // Frames from the finished recording
  const frames = await recorder.extractFrames({
    start: 0,
    end: 10,
    fps: 1,
    maxFrames: 24,
    width: 960
  });
  recorder.openFrameGallery(0);
});

await recorder.start();
// … later …
// await recorder.stop();

// Screenshots collected during the session
recorder.openScreenshotGallery(0);
// recorder.clearScreenshots();

Demos: examples/34-frame-gallery.html, examples/13-screenshot.html · Studio Tools tab

Crash recovery (IndexedDB)

With persistChunks: true (default), each MediaRecorder chunk is stored under the IndexedDB name webrec. If the tab crashes mid-record, list sessions and rebuild a Blob.

const recorder = new WebRec.ScreenCapture({
  persistChunks: true,
  timeslice: 500,
  previewOnStop: false
});

recorder.on('recover', (info) => console.log('recovered', info));

const sessions = await recorder.listRecoverableSessions();
// [{ sessionId, mimeType, startedAt, status }, ...]

const recovered = await recorder.recover(sessions[0].sessionId);
if (recovered) {
  videoEl.src = recovered.url; // also: recovered.blob, recovered.mimeType
}

await recorder.clearRecovery();          // all sessions
// await recorder.clearRecovery(sessionId); // one session

Demo: examples/15-indexeddb-recovery.html

Error handling

Failures raise or emit WebRec.ScreenCaptureError with a stable code. Always listen for error and handle rejected start() / stop() promises.

const recorder = new WebRec.ScreenCapture();

recorder.on('error', (err) => {
  console.error(err.code, err.message);
  // PERMISSION_DENIED | UNSUPPORTED | UNSUPPORTED_MIME | INVALID_STATE |
  // DEVICE_NOT_FOUND | NOT_SECURE_CONTEXT | RECORDING_FAILED |
  // STORAGE_ERROR | CANCELLED | UNKNOWN
});

recorder.on('warning', (msg) => console.warn(msg));

try {
  await recorder.start();
} catch (err) {
  const e = WebRec.normalizeError(err);
  alert(e.message);
}

Demo: examples/25-error-handling.html

Streams & live preview

While recording (or after stop for preview helpers):

const display = recorder.getDisplayStream(); // raw getDisplayMedia stream
const mixed = recorder.getMixedStream();     // display + mic/camera mix used by MediaRecorder
if (mixed) previewVideo.srcObject = mixed;

// In-progress snapshot as object URL (duration so far)
const preview = await recorder.getPreview();
// { url, blob, duration }

Events

EventPayload / use
start / pause / resume / cancel / destroyLifecycle
countdown:start / countdown / countdown:end / countdown:cancelPre-record delay after share picker ({ remaining, total })
stop{ blob, url, duration, mimeType, size, … }
progressElapsed time / size updates while recording
chunkEach MediaRecorder chunk ({ blob, index, size })
error / warning / infoDiagnostics
screenshot / screenshotsLive capture + list updates
thumbnail / framesPoster / extracted frames
controls:pipFloat bar open/close state
shareWeb Share sheet used successfully
recoverIndexedDB recovery
plugin:installPlugin installed

Plugins

Install with await recorder.use(…). Built-ins live on the WebRec global (UMD) or named ESM exports.

// Upload each chunk to your server (optional)
await recorder.use(WebRec.ChunkUploader({
  concurrency: 2,
  upload: async (chunk, ctx) => {
    await fetch('/upload', {
      method: 'POST',
      headers: { 'X-Chunk-Index': String(chunk.index) },
      body: chunk.blob
    });
  }
}));

// Auto thumbnail on stop
await recorder.use(WebRec.ThumbnailPlugin({ auto: true, width: 320 }));

// Client-side trim via MediaRecorder re-encode
const trimmer = WebRec.Trimmer();
await recorder.use(trimmer);
recorder.on('stop', async ({ blob }) => {
  const cut = await recorder.trim(blob, { start: 1, end: 10 });
  WebRec.downloadBlob(cut, 'trimmed.webm');
});

// Waveform (peer: load wavesurfer from assets/libraries/ first)
await recorder.use(WebRec.WaveformPlugin({
  container: '#wave',
  height: 64,
  waveColor: '#6c757d',
  progressColor: '#0d6efd'
}));

// FFmpeg.wasm convert — local files under assets/libraries/ffmpeg/ (no CDN)
await recorder.use(WebRec.FFmpegConvert({
  coreURL: './assets/libraries/ffmpeg/core/ffmpeg-core.js',
  wasmURL: './assets/libraries/ffmpeg/core/ffmpeg-core.wasm'
}));
// const mp4 = await recorder.convert(blob, { outputName: 'out.mp4' });
// Studio also offers one-click Download MP4 via assets/js/convert-to-mp4.js

// Keyboard shortcuts plugin (also enabled via shortcuts: true)
await recorder.use(WebRec.KeyboardShortcuts());

Demos: chunk upload, trimmer, waveform, ffmpeg

Keyboard shortcuts

Enabled by default with shortcuts: true (installs WebRec.KeyboardShortcuts()).

ShortcutAction
Alt+RStart / stop
Alt+PPause / resume
Alt+CCancel
Alt+SScreenshot (display stream)
await recorder.use(WebRec.KeyboardShortcuts({
  startStop: { altKey: true, key: 'r' },
  pauseResume: { altKey: true, key: 'p' },
  cancel: { altKey: true, key: 'c' },
  screenshot: { altKey: true, key: 's' }
}));

Demo: examples/08-keyboard-shortcuts.html

Custom plugin hooks

Any object with a name and lifecycle hooks can be installed via recorder.use(plugin):

  • install / uninstall
  • beforeStart / afterStop
  • onChunk — each MediaRecorder chunk
  • onPause / onResume / onCancel / onError
await recorder.use({
  name: 'my-analytics',
  beforeStart() { console.log('picker opening…'); },
  onChunk(_ctx, chunk) { /* chunk.blob, chunk.index */ },
  afterStop(_ctx, result) { console.log(result.size); }
});

// Upload sketch (your auth headers)
await recorder.use(WebRec.ChunkUploader({
  concurrency: 2,
  upload: async (chunk) => {
    await fetch('/api/chunks', {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer ' + token,
        'X-Chunk-Index': String(chunk.index)
      },
      body: chunk.blob
    });
  }
}));

Demos: 17-custom-plugin, 16-chunk-uploader

UI helpers

BootstrapUI is optional (docs/demos). When ui: 'bootstrap', the SDK can mount Bootstrap-styled controls; you can also build settings forms yourself:

const recorder = new WebRec.ScreenCapture({ ui: false });
const form = document.querySelector('#settings');
form.innerHTML = WebRec.BootstrapUI.settingsFormHtml(recorder.config);
form.addEventListener('change', () => {
  recorder.setOptions(WebRec.BootstrapUI.readSettingsForm(form));
});

const ui = new WebRec.BootstrapUI({ theme: 'light' });
ui.toast('Recording saved', 'success');

const { audioInputs, videoInputs } = await WebRec.MediaEngine.listDevices();

Demo: examples/18-bootstrap-settings.html

Optional peers & licenses (plain English)

Think of WebRec in three layers:

LayerWhat it isDo I need an extra license?
Core files (assets/sdk/) Screen / mic / webcam recording, toolbar, download, recovery Covered by your Envato Regular/Extended license
Demo libraries (assets/libraries/) Bootstrap, icons, fonts, lightGallery, FFmpeg.wasm (Studio MP4) MIT / OFL / GPLv3 — all free; not all are required in your production app
Optional peers WaveSurfer.js (not bundled) Not required. Free open-source if you add it yourself.

Download MP4 in Studio uses bundled FFmpeg.wasm (unminified ffmpeg-core.js + .wasm under assets/libraries/ffmpeg/core/) — no extra purchase, no CDN. Frame & screenshot galleries use bundled lightGallery (free GPLv3). See CREDITS.md.

Theming — customize look & feel (CSS variables)

You do not need to edit the SDK JavaScript to restyle the floating toolbar, preview modal, or camera PiP. Load assets/sdk/webrec.css, then override CSS variables in your own stylesheet.

1) Built-in themes

Pass a theme when creating the recorder:

const recorder = new WebRec.ScreenCapture({ theme: 'dark' });
// 'light' | 'dark' | 'minimal' | 'glass'

2) Brand colors with CSS variables

Add this to your site CSS (after the SDK stylesheet). Non-developers: ask your designer to change only the hex values.

:root {
  /* Brand */
  --sc-primary: #0f766e;           /* buttons / accents */
  --sc-primary-contrast: #ffffff;  /* text on primary buttons */
  --sc-danger: #dc3545;            /* stop / destructive */
  --sc-success: #198754;

  /* Surfaces */
  --sc-bg: #ffffff;
  --sc-surface: #f8f9fa;
  --sc-text: #212529;
  --sc-text-muted: #6c757d;
  --sc-border: #dee2e6;

  /* Shape & depth */
  --sc-toolbar-radius: 12px;
  --sc-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  --sc-font: "Segoe UI", system-ui, sans-serif;
}

3) Scope overrides to one theme class

.sc-theme-light {
  --sc-primary: #2563eb;
}
.sc-theme-dark {
  --sc-primary: #38bdf8;
  --sc-bg: #12141a;
  --sc-text: #e8eaed;
}

Full interactive demo: examples/21-css-variables-theming.html. Variable list lives in the package under src/ui/themes/variables.css.

Browser support

FeatureChrome / EdgeFirefoxSafari
Screen / window / tabYesYesPartial
System audioYes (opt-in in share UI)LimitedLimited
Microphone mixYesYesVaries
Slim float controls (popup)YesYesYes
Keep on top (Document PiP)Yes
IndexedDB recoveryYesYesYes
Preferred recordingWebM VP8/VP9WebMOften MP4
Studio Download MP4Yes (FFmpeg.wasm)YesYes

Always call WebRec.ScreenCapture.isSupported() and show a friendly fallback. Use WebRec.ScreenCapture.getCapabilities() for detailed checks (including documentPictureInPicture).

Troubleshooting

Most setup issues are browser permissions or secure-context rules. Use this checklist before opening a support ticket.

Screen / microphone / camera permission issues

  • User dismissed the share picker — Chrome/Edge show a system dialog for screen, window, or tab. If the user clicks Cancel, recording never starts. Ask them to click Record again and choose a surface.
  • Site permission blocked — If the browser previously blocked camera or microphone for your origin, the address-bar lock / site-settings icon must be used to allow Mic / Camera, then reload. Screen share is requested per session via the picker (it is not a permanent “always allow” grant like mic).
  • Not on HTTPS or localhostgetDisplayMedia and getUserMedia only work in a secure context. Production must use HTTPS. Local demos must use http://localhost (or 127.0.0.1), not file:// and not a raw LAN IP over HTTP.
  • “Permission denied” / NotAllowedError — The user denied mic/camera, or the page is not secure. Catch errors with WebRec.normalizeError and show a short message: “Allow microphone/camera in the browser prompt, or open this site over HTTPS.”
  • System audio missing — On Chrome/Edge, users must tick Share system audio (wording varies) when sharing a tab or sometimes the whole screen. Window capture often cannot include system audio. Firefox/Safari support is limited.
  • Webcam overlay blank — Confirm camera permission was granted, no other app has exclusive access to the device, and camera.enabled is true in options. Try enumerating devices (example 22).
  • iframe embeds — A cross-origin iframe needs appropriate allow attributes (e.g. display-capture, camera, microphone) or the browser will block capture.

Other common issues

  • Nothing happens on Record — Confirm WebRec.ScreenCapture.isSupported() is true and you are not on an unsupported browser.
  • Download MP4 fails — Confirm assets/libraries/ffmpeg/core/ffmpeg-core.js and ffmpeg-core.wasm are present (included in the download; see that folder’s README). First convert can take several seconds.
  • Upload plugin errors — Your server must accept the POST body size you send; raise PHP upload_max_filesize / post_max_size (or equivalent) and watch CORS if the API is on another origin.

FAQ (Envato reviewers & buyers)

No. Bootstrap is only used in documentation and optional demo UI helpers.

No. Recording is 100% client-side. Chunk upload callbacks are optional hooks for your own server.

Browser security: getDisplayMedia / getUserMedia require a secure context.

Chrome Document Picture-in-Picture remembers window size and only allows resizeTo after a click inside the PiP. Default float mode uses a slim popup instead. Enable Keep on top only when you need always-on-top; click Click to make slim if Chrome opens it tall.

No. Frames and screenshots open in a lightGallery lightbox that is bundled under its free, open-source GPLv3 license — no commercial gallery license is required. You can also swap in your own gallery. See CREDITS.md.

No. Bootstrap, Bootstrap Icons, Studio fonts, lightGallery, and FFmpeg.wasm are self-hosted under assets/libraries/. Studio, documentation, and examples use external CSS/JS files (no inline styles). preview.html is a seller capture sheet only (not part of the product runtime).

In Studio: record, then click Download MP4 (Tools) — it converts WebM→MP4 in the browser (first run loads the converter). Or use Download WebM for the original file. In your own site: use assets/js/convert-to-mp4.js or the FFmpegConvert plugin. See Download & MP4 convert.

The countdown is drawn on the Studio page when the float bar is off, so sharing that same tab/window (or Entire Screen) can capture it. Keep Float bar on so the timer shows in Document PiP / floating controls outside the captured surface, share a Window or Tab (not Entire Screen if you want the float bar excluded), and wait until recording starts before taking screenshots. See Studio tour.

No. Use the prebuilt files in assets/sdk/. Open Studio and examples over localhost or HTTPS.

Keep persistChunks: true. After reload, call listRecoverableSessions() and recover(sessionId). See Crash recovery.

Yes. Create new WebRec.ScreenCapture() on mount and call destroy() on unmount. See example 30 and Use cases.

Only surfaces the browser share picker allows. You typically record a tab/window the user selects — not privileged OS/meeting chrome the browser blocks. System audio depends on the browser and the user’s share choices.