Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Device Test Bench

A privacy-first, 100% client-side tool to test your webcam and microphone.

  • No recording by default — the camera preview is live-only and disappears when you leave the page.
  • No upload, ever — the page makes zero network requests after the initial HTML/CSS/JS load. No analytics, no telemetry, no third-party scripts, no fonts from CDNs.
  • No backend — static-only Next.js site. Host it for free on Netlify, GitHub Pages, Cloudflare Pages, or S3.
  • Explicit permissions — your browser is never asked for camera/microphone access until you click Start on the test you want.
  • OWASP-aware — strict Content-Security-Policy, Permissions-Policy, COOP/CORP, referrer policy, and X-Content-Type-Options are all set out of the box.
  • Open source, MIT licensed — read the code, run it locally, audit it.

Why

Buying a new webcam? Joining a video call from a coffee shop? Want to make sure your mic actually works before an interview? This tool does exactly that and nothing more.

Demo

Once deployed (instructions below), open the site and click Start.

Features

Camera test

  • Enumerates every connected video input device.
  • Live preview with mirror toggle (natural for front-facing cameras).
  • Snapshot button — capture the current frame as a downloadable .png (lives only in your browser tab; nothing is uploaded).
  • Switch between cameras on the fly; the list updates automatically when you plug a device in or out.

Microphone test

  • Enumerates every connected audio input device.
  • Live VU meter driven by AnalyserNode — no third-party audio library.
  • Record → play back → download as .webm. Recording is held in memory and disappears when you close the tab or click Discard.

Privacy gate

  • The very first thing the user sees is a privacy notice with a single Start button.
  • No permission prompt fires until that button is clicked.
  • Switching tabs never triggers the wrong permission.

Security model

This app does not collect information. There is no backend, no database, no analytics, no cookies, no localStorage, no IndexedDB. The page is fully static HTML/CSS/JS.

Headers set in next.config.js and replicated in public/_headers for Netlify:

Header Value
Content-Security-Policy default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; media-src 'self' blob:; connect-src 'self'; font-src 'self' data:; frame-ancestors 'none'; form-action 'self'; base-uri 'self'; object-src 'none'; upgrade-insecure-requests
Permissions-Policy camera=(self), microphone=(self), geolocation=(), interest-cohort=()
Referrer-Policy no-referrer
X-Content-Type-Options nosniff
X-Frame-Options DENY
Cross-Origin-Opener-Policy same-origin
Cross-Origin-Resource-Policy same-origin
Cross-Origin-Embedder-Policy credentialless
Strict-Transport-Security max-age=63072000; includeSubDomains; preload
X-XSS-Protection 0 (modern guidance: leave it off)
X-DNS-Prefetch-Control off
X-Download-Options noopen

OWASP Top 10 (2021) — what we do

  • A01 Broken Access Control — N/A; no server, no auth, no data.
  • A02 Cryptographic Failures — N/A; no data at rest or in transit beyond the static asset fetch.
  • A03 Injection — N/A; no server-side input. (We do avoid dangerouslySetInnerHTML and eval in client code.)
  • A04 Insecure Design — Privacy gate before any permission. No telemetry by design.
  • A05 Security Misconfiguration — All headers set; no third-party scripts; strict CSP; frame-ancestors 'none'.
  • A06 Vulnerable & Outdated Components — Pinned dependencies, CI runs npm ci and Dependabot-friendly.
  • A07 Identification & Authentication Failures — N/A; no accounts.
  • A08 Software & Data Integrity Failuresoutput: 'export' static build; next build must pass.
  • A09 Security Logging & Monitoring Failures — N/A; nothing to log. (And logging usage data would defeat the privacy promise.)
  • A10 Server-Side Request Forgery — N/A; no server.

See SECURITY.md for the threat model and how to report issues.

Browser support

Anything that supports the modern Web APIs we use. As of 2024 that includes:

  • Firefox 110+
  • Chrome / Edge 110+
  • Safari 16.4+

You must serve the site over HTTPS (or localhost) for the browser to expose camera/microphone APIs. Netlify does this automatically.

Local development

git clone https://github.com/arth2o/camera-mic-device-test-bench
cd device-test-bench
nvm use   # or ensure Node 20+
npm install
npm run dev

Open http://localhost:3000. Click Start, then Start on the camera/mic card, and grant permission when the browser prompts.

Tests

npm run lint            # next lint
npm run typecheck       # tsc --noEmit
npm test                # Vitest unit + component tests
npm run test:e2e:install  # one-time: install Playwright + Chromium
npm run test:e2e        # full E2E suite (uses Chromium with --use-fake-ui-for-media-stream)

All four must pass before opening a PR.

Deploying to Netlify

The project ships with a netlify.toml and uses Next.js output: 'export' to produce a fully static out/ directory.

Option A — one-click from GitHub

  1. Push the repo to GitHub.
  2. In Netlify, click Add new site → Import an existing project → GitHub.
  3. Select this repo. Netlify auto-detects the build settings from netlify.toml.
  4. Click Deploy site. After the build, the site is live on a *.netlify.app URL.
  5. (Optional) Add a custom domain in Domain settings.

Option B — drag & drop

  1. npm run build
  2. Drag the generated out/ folder onto https://app.netlify.com/drop.

Option C — Netlify CLI

npm install -g netlify-cli
netlify login
netlify init      # links the directory, reads netlify.toml
netlify deploy --prod

Project structure

.
├── e2e/                       # Playwright E2E suite
├── public/
│   ├── _headers               # Netlify edge security headers
│   └── robots.txt
├── src/
│   ├── app/                   # Next.js App Router (root layout, page)
│   ├── components/
│   │   ├── features/          # PrivacyGate, CameraTest, MicrophoneTest
│   │   └── ui/                # shadcn-style primitives (Button, Card, etc.)
│   ├── hooks/                 # useMediaDevices, useCameraStream, useMicrophone
│   ├── lib/                   # utils (cn, etc.)
│   └── test/                  # Vitest setup + fake-media helpers
├── .github/workflows/ci.yml   # lint + typecheck + test + build + e2e
├── next.config.js             # CSP, Permissions-Policy, output:'export'
├── playwright.config.ts
├── tailwind.config.ts
├── tsconfig.json
└── vitest.config.ts

Tech stack

  • Next.js 14 (App Router, static export)
  • React 18 + TypeScript 5 (strict mode)
  • Tailwind CSS + hand-rolled shadcn-style primitives
  • Vitest + Testing Library for unit/component tests
  • Playwright for real-browser E2E
  • Zero runtime dependencies for media: pure Web APIs (getUserMedia, enumerateDevices, MediaRecorder, AnalyserNode)

License

MIT — see LICENSE.

Acknowledgements

  • shadcn/ui for the component patterns
  • The Web Platform itself — getUserMedia, MediaRecorder, AnalyserNode do the heavy lifting

Disclaimer

This tool is provided as-is, with no warranty. Do not use it to record other people without their consent. Do not use it on shared devices expecting privacy from other users of the OS. The browser is the source of truth for permissions; this site can only ask, not grant.

About

Privacy-first, 100% client-side camera and microphone test tool. No recording, no upload, no tracking.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages