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.
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.
Once deployed (instructions below), open the site and click Start.
- 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.
- 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.
- 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.
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 |
- 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
dangerouslySetInnerHTMLandevalin 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 ciand Dependabot-friendly. - A07 Identification & Authentication Failures — N/A; no accounts.
- A08 Software & Data Integrity Failures —
output: 'export'static build;next buildmust 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.
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.
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 devOpen http://localhost:3000. Click Start, then Start on the camera/mic card, and grant permission when the browser prompts.
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.
The project ships with a netlify.toml and uses Next.js output: 'export' to produce a fully static out/ directory.
- Push the repo to GitHub.
- In Netlify, click Add new site → Import an existing project → GitHub.
- Select this repo. Netlify auto-detects the build settings from
netlify.toml. - Click Deploy site. After the build, the site is live on a
*.netlify.appURL. - (Optional) Add a custom domain in Domain settings.
npm run build- Drag the generated
out/folder onto https://app.netlify.com/drop.
npm install -g netlify-cli
netlify login
netlify init # links the directory, reads netlify.toml
netlify deploy --prod.
├── 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
- 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)
MIT — see LICENSE.
- shadcn/ui for the component patterns
- The Web Platform itself —
getUserMedia,MediaRecorder,AnalyserNodedo the heavy lifting
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.