Emerging Interfaces

Eye-Tracking Tutorial: Getting Started With Gaze Input From an Ordinary Webcam

No depth camera, no infrared rig — WebGazer.js turns a laptop webcam into a gaze estimator that self-calibrates from the clicks and cursor movements a visitor already makes.

Across capacitive touch, flex sensors, force sensing, IMU motion, EMG, and MediaPipe hand tracking, this project’s emerging-interfaces tutorials have built out a thorough map of how a body can talk to a machine — except through the eyes. WebGazer.js, built at Brown University, closes that gap using hardware almost everyone already has: a plain webcam.

What it actually estimates

WebGazer.js predicts where on the screen a viewer is looking, in real time, from webcam video — not a precise angular gaze vector like a dedicated infrared eye tracker, but a usable screen-space estimate, good enough for attention heatmaps, gaze-reactive interfaces, and accessibility input. It runs entirely in the browser; no video frame ever has to leave the client, which matters both for privacy and for not needing a server round-trip per frame.

Step 1 — Load it

<script src="https://webgazer.cs.brown.edu/webgazer.js" type="text/javascript"></script>

One script tag, no build step, no server component.

webgazer.setGazeListener((data, elapsedTime) => {
  if (data == null) return;
  const { x, y } = data; // predicted gaze point, in page coordinates
}).begin();

The browser’s own webcam permission prompt handles consent — WebGazer never needs you to build your own. Nothing fires until the user grants camera access.

Step 3 — The self-calibration trick

This is the part that makes WebGazer usable without a dedicated calibration screen: it treats every click and cursor movement the user already makes as a training example, on the assumption that where you click is close to where you were just looking. There’s no explicit “look at these nine dots” step required — the model improves passively as the page is used normally. You can still add an optional calibration step for higher accuracy, but it’s not load-bearing the way it is for most gaze systems.

webgazer.params.showVideoPreview = true; // see the face-tracking rectangle while testing
webgazer.params.showGazeDot = true;      // show the current prediction as a dot

Leave both of those on while developing, and turn them off before shipping.

Step 4 — Know what degrades accuracy

Gaze estimation from a 2D webcam is inherently noisier than a depth- or IR-based system. The practical failure modes:

  • Head movement. Estimates drift as the viewer’s head moves relative to the camera — design for coarse regions of the screen (quadrants, large zones) rather than pixel-precise targets.
  • Lighting. Strong backlighting or very low light degrades the underlying face-landmark tracking the whole system depends on.
  • Glasses and reflections. Glare across lenses is the single most common cause of a gaze estimate silently going stale.

Where this fits

Pair gaze with a dwell-time trigger rather than a tap or click, and you get a hands-free selection mechanism — the same pattern this project’s accessibility-adjacent tutorials (flex sensors, EMG) have used for people who can’t reliably use a mouse or touchscreen. Gaze estimated from a $0 webcam won’t replace a clinical eye tracker, but as a coarse, zero-hardware-cost input channel, it’s the missing primitive in this topic’s own sensor coverage.