Face detection in video sounds like a small feature until you start building it.
A camera opens. A person moves. The lighting changes. The face turns sideways. The browser drops frames. Mobile devices get hot. Suddenly, “draw a box around a face” becomes a real-time computer vision problem.
The good news: JavaScript can handle it. You can detect faces directly in the browser with modern web APIs and machine learning models. You can use the user’s webcam, process video frame by frame, draw boxes on a canvas, and build useful features without sending every frame to a server.
This guide shows how to detect faces in a video with JavaScript, what tools you can use, and which approach makes the most sense for different teams.
We’ll cover:
- Browser camera access with JavaScript
- Face detection with MediaPipe
- How to draw bounding boxes over video
- How MediaPipe compares with TensorFlow.js, face-api.js, native browser APIs, and server-side APIs
- What businesses, developers, creators, and product teams can build with face detection
- Privacy, performance, and testing tips
What Face Detection Means
Face detection finds where faces appear in an image or video frame.
It usually returns:
| Output | Meaning |
| Bounding box | The face location in the frame |
| Confidence score | How sure the model is |
| Keypoints | Points like eyes, nose, or mouth, depending on the model |
| Multiple detections | All faces found in the frame |
Face detection does not automatically identify who the person is. That would be face recognition. Detection answers: “Is there a face here, and where is it?”
That distinction matters for privacy and product design. A video app that uses face detection to keep a speaker centered is very different from an app that identifies people by name.
Which JavaScript Face Detection Approach Should You Use?
There are several ways to detect faces in video with JavaScript.
| Approach | Best for | Main benefit | Watch out for |
| MediaPipe Face Detector | Real-time browser apps | Fast, modern, browser-friendly | Requires model setup |
| TensorFlow.js face detection | Developers already using TensorFlow.js | Flexible ML ecosystem | More model/runtime choices to manage |
| face-api.js | Demos and older projects | Popular and easy to understand | Maintenance and model age need review |
| Native FaceDetector API | Simple browser-native experiments | No external model package | Limited browser support |
| Server-side API | Compliance, storage, backend processing | Centralized processing | Latency and privacy concerns |
For most new JavaScript projects, MediaPipe Face Detector is the best first choice. Google’s MediaPipe Face Detector docs describe it as a model for detecting faces in images and video. It works well for real-time web experiences.
Why We Can Write About This
Our team has worked with AI APIs, developer tools, computer vision workflows, and web automation for around 6 years. For this guide, we reviewed current browser docs, MediaPipe documentation, TensorFlow.js resources, and face detection research.
The research matters because face detection has a long technical history. The classic Viola-Jones paper helped popularize real-time face detection in the early 2000s. More recent models like BlazeFace were designed for fast face detection on mobile GPUs. That is the kind of work behind modern browser-friendly face detection.
Step 1: Create the HTML
We’ll build a simple page with:
- A video element for the webcam feed
- A canvas overlay for face boxes
- A button to start the camera
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Face Detection in Video</title>
<style>
body {
font-family: Arial, sans-serif;
background: #111827;
color: white;
display: flex;
justify-content: center;
padding: 40px;
}
.app {
width: 720px;
}
.video-wrap {
position: relative;
width: 720px;
height: 405px;
background: #000;
overflow: hidden;
border-radius: 8px;
}
video,
canvas {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
canvas {
pointer-events: none;
}
button {
margin-top: 16px;
padding: 10px 14px;
border: 0;
border-radius: 6px;
cursor: pointer;
font-weight: 600;
}
#status {
margin-top: 12px;
color: #d1d5db;
}
</style>
</head>
<body>
<div class="app">
<h1>Face Detection in Video</h1>
<div class="video-wrap">
<video id="video" autoplay playsinline muted></video>
<canvas id="canvas"></canvas>
</div>
<button id="startButton">Start camera</button>
<p id="status">Camera is off.</p>
</div>
<script type="module" src="./app.js"></script>
</body>
</html>
This gives us a clean base. The video shows the webcam. The canvas sits on top and draws the detected face boxes.
Step 2: Access the Camera
The browser camera comes from navigator.mediaDevices.getUserMedia().
MDN’s getUserMedia documentation explains that it asks the user for access to media devices, such as a camera or microphone. In most browsers, this works only on HTTPS or localhost.
Create an app.js file:
const video = document.getElementById("video");
const canvas = document.getElementById("canvas");
const statusText = document.getElementById("status");
const startButton = document.getElementById("startButton");
const ctx = canvas.getContext("2d");
async function startCamera() {
const stream = await navigator.mediaDevices.getUserMedia({
video: {
width: 720,
height: 405,
facingMode: "user"
},
audio: false
});
video.srcObject = stream;
await new Promise((resolve) => {
video.onloadedmetadata = resolve;
});
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
statusText.textContent = "Camera is running.";
}
startButton.addEventListener("click", async () => {
try {
await startCamera();
} catch (error) {
console.error(error);
statusText.textContent = "Could not access camera.";
}
});
At this point, the browser can show webcam video. Next, we add face detection.
Step 3: Add MediaPipe Face Detector
MediaPipe provides ready-to-use vision models for the web. The current MediaPipe Tasks Vision package can run models in the browser through WebAssembly and GPU acceleration when available.
Install with npm:
npm install @mediapipe/tasks-vision
For a quick browser demo, you can also import from a CDN.
Update app.js:
import {
FaceDetector,
FilesetResolver
} from "https://cdn.jsdelivr.net/npm/@mediapipe/[email protected]";
const video = document.getElementById("video");
const canvas = document.getElementById("canvas");
const statusText = document.getElementById("status");
const startButton = document.getElementById("startButton");
const ctx = canvas.getContext("2d");
let faceDetector;
let lastVideoTime = -1;
async function createFaceDetector() {
const vision = await FilesetResolver.forVisionTasks(
"https://cdn.jsdelivr.net/npm/@mediapipe/[email protected]/wasm"
);
faceDetector = await FaceDetector.createFromOptions(vision, {
baseOptions: {
modelAssetPath:
"https://storage.googleapis.com/mediapipe-models/face_detector/blaze_face_short_range/float16/latest/blaze_face_short_range.tflite",
delegate: "GPU"
},
runningMode: "VIDEO"
});
}
This loads the MediaPipe face detector model. The runningMode: “VIDEO” option tells MediaPipe that we will process a stream over time, not a single still image.
Step 4: Detect Faces Frame by Frame
Now we need a loop.
The browser gives us video frames. MediaPipe checks each frame. Canvas draws the boxes.
Add this function:
function drawDetections(detections) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (const detection of detections) {
const box = detection.boundingBox;
ctx.strokeStyle = "#22c55e";
ctx.lineWidth = 3;
ctx.strokeRect(
box.originX,
box.originY,
box.width,
box.height
);
const score = detection.categories?.[0]?.score ?? 0;
ctx.fillStyle = "#22c55e";
ctx.font = "16px Arial";
ctx.fillText(
`Face ${(score * 100).toFixed(1)}%`,
box.originX,
Math.max(box.originY - 8, 20)
);
}
}
function detectFaces() {
if (!faceDetector || video.readyState < 2) {
requestAnimationFrame(detectFaces);
return;
}
if (video.currentTime !== lastVideoTime) {
lastVideoTime = video.currentTime;
const startTimeMs = performance.now();
const result = faceDetector.detectForVideo(video, startTimeMs);
drawDetections(result.detections);
}
requestAnimationFrame(detectFaces);
}
Then update the button handler:
startButton.addEventListener("click", async () => {
try {
statusText.textContent = "Loading face detector...";
await createFaceDetector();
await startCamera();
statusText.textContent = "Detecting faces.";
detectFaces();
} catch (error) {
console.error(error);
statusText.textContent = "Could not start face detection.";
}
});
Now the app can:
Open camera → Read video frame → Detect faces with MediaPipe → Draw bounding boxes on canvas → Repeat in real time
Full JavaScript Example
Here is the full app.js in one place:
import {
FaceDetector,
FilesetResolver
} from "https://cdn.jsdelivr.net/npm/@mediapipe/[email protected]";
const video = document.getElementById("video");
const canvas = document.getElementById("canvas");
const statusText = document.getElementById("status");
const startButton = document.getElementById("startButton");
const ctx = canvas.getContext("2d");
let faceDetector;
let lastVideoTime = -1;
async function createFaceDetector() {
const vision = await FilesetResolver.forVisionTasks(
"https://cdn.jsdelivr.net/npm/@mediapipe/[email protected]/wasm"
);
faceDetector = await FaceDetector.createFromOptions(vision, {
baseOptions: {
modelAssetPath:
"https://storage.googleapis.com/mediapipe-models/face_detector/blaze_face_short_range/float16/latest/blaze_face_short_range.tflite",
delegate: "GPU"
},
runningMode: "VIDEO"
});
}
async function startCamera() {
const stream = await navigator.mediaDevices.getUserMedia({
video: {
width: 720,
height: 405,
facingMode: "user"
},
audio: false
});
video.srcObject = stream;
await new Promise((resolve) => {
video.onloadedmetadata = resolve;
});
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
}
function drawDetections(detections) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (const detection of detections) {
const box = detection.boundingBox;
const score = detection.categories?.[0]?.score ?? 0;
ctx.strokeStyle = "#22c55e";
ctx.lineWidth = 3;
ctx.strokeRect(box.originX, box.originY, box.width, box.height);
ctx.fillStyle = "#22c55e";
ctx.font = "16px Arial";
ctx.fillText(
`Face ${(score * 100).toFixed(1)}%`,
box.originX,
Math.max(box.originY - 8, 20)
);
}
}
function detectFaces() {
if (!faceDetector || video.readyState < 2) {
requestAnimationFrame(detectFaces);
return;
}
if (video.currentTime !== lastVideoTime) {
lastVideoTime = video.currentTime;
const result = faceDetector.detectForVideo(
video,
performance.now()
);
drawDetections(result.detections);
}
requestAnimationFrame(detectFaces);
}
startButton.addEventListener("click", async () => {
try {
statusText.textContent = "Loading face detector...";
await createFaceDetector();
await startCamera();
statusText.textContent = "Detecting faces.";
detectFaces();
} catch (error) {
console.error(error);
statusText.textContent = "Could not start face detection.";
}
});
MediaPipe vs TensorFlow.js vs face-api.js
You have several options for face detection in JavaScript. Here is the practical comparison.
| Tool | Best for | Strength | Weakness |
| MediaPipe Face Detector | Modern real-time browser apps | Fast and maintained by Google | Setup feels more detailed at first |
| TensorFlow.js face detection | ML-heavy JavaScript apps | Flexible model ecosystem | More choices to manage |
| face-api.js | Simple demos and older tutorials | Easy examples and familiar API | Check maintenance before production |
| Native FaceDetector API | Experiments in supported browsers | Browser-native idea | Limited browser support |
| Server-side API | Backend workflows | Central control and storage | More latency and privacy review |
When MediaPipe Is the Best Choice
Use MediaPipe when you need real-time detection in the browser.
Good use cases:
| Use case | Why MediaPipe fits |
| Video filters | Fast local detection |
| Camera framing | Works in real time |
| Virtual try-on | Needs face position quickly |
| Creator tools | Runs without uploading every frame |
| Browser demos | Strong model quality with manageable setup |
MediaPipe is also a good fit for mobile browsers because models like BlazeFace were designed for fast face detection on devices. The BlazeFace paper describes a lightweight face detector made for mobile GPU inference, which is exactly the kind of design that helps with browser camera apps.
When TensorFlow.js Makes More Sense
TensorFlow.js lets developers run machine learning models in JavaScript. The TensorFlow.js ecosystem has included face detection options and models that can run in the browser.
Choose TensorFlow.js if your app already uses it for other ML tasks.
For example:
| App | Why TensorFlow.js may fit |
| Browser ML dashboard | One ML runtime for several models |
| Custom model experiments | More control over model pipeline |
| Education project | Good for learning ML in JavaScript |
| Research demo | Easier to inspect model behavior |
Compared with MediaPipe, TensorFlow.js can feel more flexible. MediaPipe usually feels more direct for production-style real-time vision tasks.
When face-api.js Is Enough
face-api.js became popular because it made face detection, landmarks, and recognition approachable in JavaScript. Many older tutorials use it.
It can still be useful for demos, prototypes, and learning projects.
Good use cases:
| Use case | Why it fits |
| Learning face detection | Many examples exist |
| Quick prototype | Simple API style |
| Small internal demo | Good enough for tests |
Before using it in a production app, check current maintenance, model quality, browser performance, and security expectations. For a new app in 2026, MediaPipe is usually the stronger first test.
What About the Native FaceDetector API?
Some browsers have worked on a native FaceDetector API as part of the Shape Detection API. MDN’s FaceDetector page notes that browser support is limited.
A native API can be nice because you do not need to ship your own model files. The problem is cross-browser support. If your users are on different browsers and devices, test carefully before relying on it.
Native face detection can fit:
| Use case | Fit |
| Browser experiment | Good |
| Chrome-only internal tool | Possible |
| Public production app | Risky |
| Cross-browser app | Use MediaPipe instead |
When a Server-Side API Makes Sense
Client-side detection is great for speed and privacy. Server-side processing can still make sense for some workflows.
Use a backend API when:
| Need | Why server-side helps |
| Uploaded video files | Process after upload |
| Compliance logging | Centralized records |
| Large batch jobs | Easier to run in backend queue |
| Multiple AI steps | Combine face detection, OCR, transcription, moderation |
| Team dashboards | Store results in a database |
The tradeoff is latency and privacy. Sending video frames to a server means you must think about storage, retention, consent, and security.
A server workflow may look like this:
User uploads video → Backend stores file → Worker extracts frames → Face detector runs on selected frames → Results are saved as timestamps and boxes → Dashboard shows face count and time ranges
For live camera features, browser-side detection is usually better. For archive processing and reporting, backend processing can be easier to manage.
Who Benefits from Face Detection in Video?
Businesses
Businesses can use face detection to improve video workflows without manually reviewing every frame.
| Business use case | Example |
| Video quality checks | Confirm a speaker appears in frame |
| Meeting tools | Center the active speaker |
| E-learning | Check whether a presenter is visible |
| Retail analytics | Count visible faces in public-facing media with consent |
| Media libraries | Tag video segments that contain people |
| Creator platforms | Add auto-crop or face-aware thumbnails |
Businesses should keep the use case narrow. Face detection is most useful when it improves a clear workflow: framing, tagging, review, accessibility, or editing.
Developers
Developers benefit because face detection can run directly in the browser.
That means:
| Developer benefit | Why it helps |
| Lower server cost | No need to upload every frame |
| Lower latency | Detection happens on-device |
| Better privacy design | Raw camera feed can stay local |
| Easier UI effects | Canvas overlays update in real time |
| Faster prototypes | One HTML page can prove the concept |
For production, developers should optimize frame rate, memory usage, and model loading. A detector that works on a laptop may run slowly on low-end phones.
Product Teams
Product teams can use face detection for features users actually notice.
Examples:
| Feature | User benefit |
| Auto-framing | Keeps the person centered |
| Blur background trigger | Applies effect when a face is found |
| Face-aware cropping | Better thumbnails |
| Video recording checks | Warns if no face is visible |
| Creator filters | Adds effects in the right location |
The product question is not “can we detect a face?” The useful question is “what better experience does detection create?”
Creators and Media Teams
Creators can use face detection for editing and automation.
Examples:
| Workflow | How face detection helps |
| Shorts creation | Find segments with a speaker on screen |
| Thumbnail generation | Pick frames with clear faces |
| Video cleanup | Flag shots where the subject is missing |
| Auto-cropping | Keep faces inside vertical video |
| Effects | Attach overlays to face position |
This is where browser tools can be very useful. A creator app can preview effects live without waiting for backend processing.
Privacy and Safety Notes
Face detection touches sensitive data because it uses camera video and images of people.
Use these rules:
| Rule | Why |
| Ask for camera permission clearly | Users should know what happens |
| Process locally when possible | Reduces data exposure |
| Avoid storing raw video unless needed | Lowers privacy risk |
| Explain what is detected | Face location, count, or landmarks |
| Do not identify people unless required | Recognition has higher risk |
| Add opt-out controls | Important for trust |
| Review laws for your market | Biometrics rules vary by region |
For browser apps, a strong privacy pattern is:
Camera opens locally → Face detection runs in browser → Only box coordinates or counts are used → No raw frames are uploaded
If the app sends frames or videos to a server, disclose that clearly and review retention rules.
Performance Tips
Real-time video detection can be heavy. Small changes help a lot.
| Tip | Why it helps |
| Use lower video resolution | Fewer pixels to process |
| Process every 2nd or 3rd frame | Reduces CPU/GPU load |
| Use requestAnimationFrame | Syncs with browser rendering |
| Prefer GPU delegate when available | Faster inference |
| Stop camera when done | Saves battery |
| Avoid drawing too much | Canvas work can become expensive |
| Test on mobile devices | Mobile performance is different |
If detection feels slow, start by lowering the camera resolution:
video: {
width: 480,
height: 270,
facingMode: "user"
}
You can also skip frames:
let frameCount = 0;
function detectFaces() {
frameCount++;
if (frameCount % 2 === 0) {
const result = faceDetector.detectForVideo(video, performance.now());
drawDetections(result.detections);
}
requestAnimationFrame(detectFaces);
}
That cuts detection work roughly in half.
Testing Checklist
Test with real conditions, not only one perfect webcam scene.
| Test | Why |
| Bright light | Checks normal conditions |
| Low light | Common failure case |
| Side profile | Tests non-front-facing faces |
| Glasses | Can affect detection |
| Hats or masks | May hide face features |
| Multiple people | Checks multi-face detection |
| Fast movement | Tests frame stability |
| Mobile browser | Checks performance |
| Different skin tones | Helps spot quality issues |
| Different camera angles | Real users move around |
Face detection should be tested across devices and environments. A model can look excellent in a clean demo and still struggle in real rooms.
Where LLMAPI Can Fit
Face detection gives you visual signals. In many business workflows, those signals are only one part of the full automation.
For example:
Video upload → Face detection finds speaker timestamps → Speech-to-text creates transcript → LLMAPI summarizes key moments → Dashboard shows clips, transcript, and summary
Or:
Webcam recording → Face detection confirms person is visible → App stores metadata → LLMAPI creates a QA report from transcript and event data
LLMAPI can help when face detection connects to text, summaries, classification, moderation, or workflow routing. The face detector handles visual location. LLMAPI can help process the surrounding text and metadata.
Final Recommendation
For most JavaScript apps in 2026, start with MediaPipe Face Detector.
It is fast, modern, and suitable for real-time browser video. Use getUserMedia() to access the camera, MediaPipe to detect faces, and canvas to draw boxes.
Choose another path when the project calls for it:
| Need | Best choice |
| Real-time browser detection | MediaPipe Face Detector |
| Existing TensorFlow.js app | TensorFlow.js |
| Learning/demo project | face-api.js |
| Browser-native experiment | FaceDetector API |
| Uploaded video processing | Server-side API or backend model |
| Multi-step AI workflow | Face detection + LLMAPI |