screen-recorder-benchmark

August 30, 2026 · View on GitHub

How long does it take to export a finished product demo? Same recording, same edit, same stopwatch, across the desktop apps built to make them — with every result verified in pixels and audio before it counts.

Results: https://etiennelescot.github.io/screen-recorder-benchmark/

Run it

git clone https://github.com/EtienneLescot/screen-recorder-benchmark
cd screen-recorder-benchmark && npm install

node bench.mjs doctor      # is this machine fit to measure?
node bench.mjs apps        # what can it measure, and what is missing
node bench.mjs preflight   # the one interactive step — grant everything here
node bench.mjs install     # unattended
node bench.mjs calibrate   # once per machine
node bench.mjs run --bundle commons-upload
node bench.mjs report

npm run doctor, npm run apps, … are shorthand for the same commands.

Choosing what to measure

node bench.mjs apps lists every tool, whether it is installed, and what is blocking it if anything:

tool                  status        version         driven by
openscreen-cli        ready         1.10.0-rc.3     cli
cap                   ready         0.5.9           cli
screen-studio         blocked       3.7.5-4595      cdp+menu
                      ↳ export requires an activated licence — there is no trial export
ffmpeg-baseline       ready         8.1.2           cli

Then pick any set:

node bench.mjs run --bundle commons-upload --apps cap,openscreen-cli

ffmpeg-baseline is added automatically and is not a competitor — it is the unit everything else is divided by. A run needs at least two tools to produce a usable measurement, and which two is up to you.

What is measured

A finished demo export, not a transcode: a wallpaper background the compositor samples per pixel, padding, rounded corners, a drop shadow, three animated zooms, motion blur, a cursor rendered from telemetry — sprite, smoothing, its own motion blur, click effects — a webcam inset with mask and shadow, and the recording's audio, all pinned to 1920×1080 / 60 fps / H.264 / MP4 for every tool.

The cursor matters more than it looks. Every tool here hides the system pointer while recording and re-draws it at export time from a sidecar; painting a cursor into the source would exercise none of that. It is supplied as telemetry and the source is left clean.

Full definition, including the S0→S4 ladder: PROTOCOL.md.

What a result means

Quote Cost (×floor), not seconds. A plain ffmpeg transcode of the same clip, with no compositing, is measured immediately before each tool runs — so every tool is divided by a reference from the same hardware under the same load, minutes earlier. A tool at 1.26× did 26 % more work than a bare re-encode, on whatever machine you have. Seconds compare a machine to itself and nothing else.

Every export is re-probed and inspected before it counts: resolution, frame rate, codec and duration against the target; wallpaper, padding, corner radius, zooms, cursor and camera in the pixels; and audio by loudness, because a silent track passes any check that only asks whether audio exists. A tool reports what it configured; the verifier decides what happened, and the verifier wins.

Two conditions will ruin your numbers and both are checked: background load, reported per tool, and remote-desktop sessions — Parsec, Screen Sharing, RDP and ARD encode the screen through the same hardware H.264 block the exports use, which no CPU measurement sees and which affects tools unequally.

Contributing a measurement

node bench.mjs run --bundle commons-upload --apps <two or more tools>
node bench.mjs submit --run <runId> --as "your name" > submissions/<platform>/<chip>-<date>.json

Open a PR. CI validates it against schema/submission.schema.json and regenerates the site.

Submissions are combined as a graph of ratios, not an average: tools are nodes, every pair measured together on one machine is an edge, and the global ranking is recovered by least squares over all of them. So no particular tool is required in a submission — the graph recomposes as long as submissions overlap, and where they overlap redundantly, the disagreement between them is published.

A submission is rejected for failing the schema, carrying fewer than two verified tools, or using footage nobody else can obtain. Nothing else.

Roster

Membership follows what a tool is for — turning a screen recording into a finished demo — not whether an adapter happens to exist. General-purpose editors and plain recorders are out even when they can be driven. The roster is per-platform, and an empty cell is a result: CANDIDATES.md.

Footage

Reproducible elsewhereRealisticUse for
Public bundle--bundleyes, hash-checkedyessubmissions
Generated fixture — defaultyes, from a seednodevelopment, CI
Local recording — --sourcenoyesinvestigation

Public bundles are downloaded from permanent Wikimedia URLs, verified against a sha256, and normalised to H.264/MP4 with parameters recorded in the manifest — so two machines can prove they measured the same footage. Attribution: CREDITS.md.

Platforms

macOS, Windows and Linux. lib/platform.mjs holds everything that differs — process sampling, hardware and power state, installation, encoder selection — and the measurement core is platform-independent, because two platforms that time things differently stop measuring the same thing.

On Linux the roster is shorter, and that is a fact about the products rather than about the adapters: OpenScreen, Cap and Recordly ship a Linux build; Screen Studio and FocuSee do not. Nothing is installed system-wide, because the harness takes no root — OpenScreen and Recordly come from the vendors' AppImages, extracted rather than run in place (an AppImage self-mounts through libfuse2, which Ubuntu has not shipped by default since 22.04), and Cap's .deb is unpacked with dpkg-deb -x.

Two things there are not what they are elsewhere, and both are recorded in every run rather than assumed:

  • The floor encodes through VAAPI. h264_amf is a Windows runtime, and a full ffmpeg build advertises nvenc and qsv on hardware that cannot open either — so an AMD or Intel machine that only tried those fell through to libx264 and measured a software floor, which is not comparable to anyone else's.
  • Recordly exports on its Legacy pipeline. Its Lightning path is not shipped for Linux: the panel offers the control and the export then refuses, naming the missing encoder path itself. Legacy is WebCodecs, it is what a user on this platform gets, and every run records which pipeline produced it.

Layout

bench.mjs              entrypoint
apps.mjs               the registry and what each machine can measure
sources.json           public footage bundles, with hashes and licences
roster.json            roster membership per platform
scenarios/index.mjs    the scenario and the pinned output target
lib/runner.mjs         the shared clock every adapter is timed by
lib/measure.mjs        stopwatch, process sampling, output + audio verification
lib/visualCheck.mjs    pixel verification of the effects
lib/aggregate.mjs      the ratio graph and its solver
lib/publicSource.mjs   fetch, verify and normalise public footage
lib/platform.mjs       everything that differs between macOS and Windows
drivers/               one per tool — see drivers/README.md for the contract
submissions/           contributed measurements
docs/                  the published site, regenerated from submissions/

Licence

MIT. The footage it downloads is other people's work under its own licences — see CREDITS.md.

Before you push

npm run verify

Runs exactly what CI runs: the submission schema, the unit tests, the linter, and a rebuild of docs/ checked against what is committed. npm run fix applies the formatting and regenerates the site.