Setup guides
USB webcam (fastest start)
- Plug the webcam into a computer inside your home network.
- On any device: log in, Dashboard → Add a camera
→ type
USB webcam. - On the computer with the webcam: open Connect for that camera.
- Allow camera access when the browser asks, then press Start pushing. Leave the tab open.
Feeds are live while a Connect tab is open on your LAN. Closing the tab pauses the feed.
IP camera (snapshot polling)
- Find your camera's snapshot URL — commonly something like
http://192.168.1.50/snapshot.jpgorhttp://camera.local/cgi-bin/snapshot.cgi. Check the camera's manual or web UI. - Dashboard → Add a camera → type
IP camera→ paste that LAN URL. - Open Connect for the camera on a LAN machine.
Honest limitation: browsers can only read LAN camera images if the camera permits cross-origin access (CORS). Most IP cams don't send CORS headers, so the page may be able to display the feed but not forward it. If your camera blocks CORS, use the USB path or an NVR relay — or keep that camera on the roadmap (a tiny always-on agent is planned).
NVR — one dashboard camera per channel
- Each NVR channel becomes its own WholeHomeCam camera: Dashboard →
Add a camera → type
NVR channel. - Set Device / NVR to the same name for every channel on one
box — e.g.
NVR Loft 192.168.0.214. Cameras with the same device name group together on the dashboard; set Channel # so they sort sensibly. - For LAN source URL, paste that channel's snapshot URL —
e.g.
http://192.168.0.214/cgi-bin/snapshot.cgi?chn=1(the exact path varies by NVR brand; check its web UI/API docs). - Open Connect for a channel on a LAN machine to start pushing. One Connect tab per channel you want live.
Note: NVR snapshot endpoints need digest auth and send no CORS headers, so the browser connector usually can't forward NVR frames — use the agent below for always-on ingest.
whc-agent — auto-discovery + enrollment
agent/whc-agent.mjs is a zero-dependency Node script that
runs on any machine inside your network. It does what browsers can't:
digest-auth HTTP polling, ONVIF (WS-Discovery) multicast discovery, and
port sweeps.
Fully automatic: Settings shows a ready-made enroll command containing your scoped agent token:
node whc-agent.mjs enroll https://wholehomecam.com <token> admin <nvr-password> 192.168.0
That one command scans the LAN, probes each NVR's channels
(/cgi-bin/snapshot.cgi?channel=N, digest auth), registers a
camera for every live channel — grouped by device automatically — writes
agent.json, and starts pushing snapshots. Re-running it is
safe: existing channels are matched by (device, channel) and reused, not
duplicated.
The agent token is a capability scoped to creating
cameras on your account — it can't read or control anything.
Regenerate it from Settings if it leaks. Keep
agent.json private: it holds NVR credentials and ingest keys.
Manual mode still exists for odd setups:
scan (discovery report only) and push agent.json
(poll a hand-written config). Amcrest NV4108 (Dahua) channels are
1-based on this firmware — verified against NV4108E.
Commands
From a camera's page you can queue commands for its connector: start/stop recording, arm/disarm alerts, privacy mode on/off. The connector polls every few seconds and executes them — the dashboard doesn't need the Connect tab open to queue a command, only to execute it.
Thumbnails & slow networks
Camera frames can be large (4K NVR snapshots run ~2 MB). The dashboard, live grid, and camera pages all load thumbnails — typically ~13 KB per tile — so the full grid works on weak cellular or rural links. Click any image for the full-resolution frame.
Thumbs are produced where the frame originates: NVR agents pull the
hardware-encoded substream (subtype=1, ~20 KB), and the
browser connector re-encodes a 480px tile alongside each frame. Channels
without a substream simply fall back to the full image.
Built on ALB
WholeHomeCam is built on the ALB language stack. The motion pipeline that classifies every frame — people, vehicles, and other moving subjects — is a WebAssembly module compiled from ALB source by the ALB toolchain. The same toolchain serves the pages you're reading: compiled modules, no framework runtime. Learn more at alb-lang.org.