The MediaPipe Face Landmarker task lets you detect face landmarks and facial expressions in images and videos. You can use this task to identify human facial expressions, apply facial filters and effects, and create virtual avatars. This task uses machine learning (ML) models that can work with single images or a continuous stream of images. The task outputs 3-dimensional face landmarks, blendshape scores (coefficients representing facial expression) to infer detailed facial surfaces in real time, and transformation matrices to perform the transformations required for effects rendering.
Quickstart
Install the SDK for your platform, prepare input data, choose a running mode, and run inference.
Web
Image
import { FilesetResolver, FaceLandmarker } from "@mediapipe/tasks-vision"; const vision = await FilesetResolver.forVisionTasks( "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm" ); const faceLandmarker = await FaceLandmarker.createFromOptions(vision, { baseOptions: { modelAssetPath: "face_landmarker.task", delegate: "GPU" }, runningMode: "IMAGE", numFaces: 1, outputFaceBlendshapes: true, }); // Synchronous single-frame call (stateless across images) const image = document.getElementById("image") as HTMLImageElement; const result = faceLandmarker.detect(image);
Video
import { FilesetResolver, FaceLandmarker } from "@mediapipe/tasks-vision"; const vision = await FilesetResolver.forVisionTasks( "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm" ); const faceLandmarker = await FaceLandmarker.createFromOptions(vision, { baseOptions: { modelAssetPath: "face_landmarker.task", delegate: "GPU" }, runningMode: "VIDEO", numFaces: 1, outputFaceBlendshapes: true, }); // Synchronous across decoded frames with monotonic timestamps (never drops frames) for (const { frame, timestampMs } of decodedVideoFrames) { const result = faceLandmarker.detectForVideo(frame, timestampMs); }
Livestream
import { FilesetResolver, FaceLandmarker } from "@mediapipe/tasks-vision"; const vision = await FilesetResolver.forVisionTasks( "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm" ); // On Web, live camera loops pair runningMode: "VIDEO" with requestAnimationFrame const faceLandmarker = await FaceLandmarker.createFromOptions(vision, { baseOptions: { modelAssetPath: "face_landmarker.task", delegate: "GPU" }, runningMode: "VIDEO", numFaces: 1, outputFaceBlendshapes: true, }); const video = document.getElementById("webcam") as HTMLVideoElement; video.srcObject = await navigator.mediaDevices.getUserMedia({ video: true }); await video.play(); let lastVideoTime = -1; function renderLoop() { if (video.readyState >= 2 && video.currentTime !== lastVideoTime) { lastVideoTime = video.currentTime; const result = faceLandmarker.detectForVideo(video, performance.now()); console.log(result.faceLandmarks, result.faceBlendshapes); } requestAnimationFrame(renderLoop); } renderLoop();
Android (Kotlin)
Image
import com.google.mediapipe.framework.image.BitmapImageBuilder import com.google.mediapipe.framework.image.MPImage import com.google.mediapipe.tasks.core.BaseOptions import com.google.mediapipe.tasks.vision.core.RunningMode import com.google.mediapipe.tasks.vision.facelandmarker.FaceLandmarker val baseOptions = BaseOptions.builder() .setModelAssetPath("face_landmarker.task") .build() val options = FaceLandmarker.FaceLandmarkerOptions.builder() .setBaseOptions(baseOptions) .setRunningMode(RunningMode.IMAGE) .setNumFaces(1) .setOutputFaceBlendshapes(true) .build() val faceLandmarker = FaceLandmarker.createFromOptions(context, options) // Synchronous single-image call (no temporal tracking across calls) val mpImage = BitmapImageBuilder(bitmap).build() val result = faceLandmarker.detect(mpImage)
Video
import com.google.mediapipe.framework.image.BitmapImageBuilder import com.google.mediapipe.framework.image.MPImage import com.google.mediapipe.tasks.core.BaseOptions import com.google.mediapipe.tasks.vision.core.RunningMode import com.google.mediapipe.tasks.vision.facelandmarker.FaceLandmarker val baseOptions = BaseOptions.builder() .setModelAssetPath("face_landmarker.task") .build() val options = FaceLandmarker.FaceLandmarkerOptions.builder() .setBaseOptions(baseOptions) .setRunningMode(RunningMode.VIDEO) .setNumFaces(1) .setOutputFaceBlendshapes(true) .build() val faceLandmarker = FaceLandmarker.createFromOptions(context, options) // Synchronous: processes every frame in order with monotonic timestamps (no frame drops) val mpImage = BitmapImageBuilder(frameBitmap).build() val result = faceLandmarker.detectForVideo(mpImage, frameTimestampMs)
Livestream
import android.os.SystemClock import android.util.Log import com.google.mediapipe.framework.image.BitmapImageBuilder import com.google.mediapipe.framework.image.MPImage import com.google.mediapipe.tasks.core.BaseOptions import com.google.mediapipe.tasks.vision.core.RunningMode import com.google.mediapipe.tasks.vision.facelandmarker.FaceLandmarker val baseOptions = BaseOptions.builder() .setModelAssetPath("face_landmarker.task") .build() val options = FaceLandmarker.FaceLandmarkerOptions.builder() .setBaseOptions(baseOptions) .setRunningMode(RunningMode.LIVE_STREAM) .setNumFaces(1) .setOutputFaceBlendshapes(true) .setResultListener { result, _ -> val faces = result.faceLandmarks() } .setErrorListener { error -> Log.e("MediaPipe", error.message.orEmpty()) } .build() val faceLandmarker = FaceLandmarker.createFromOptions(context, options) // Async: automatically drops incoming camera frames when busy so results stay current faceLandmarker.detectAsync(mpImage, SystemClock.uptimeMillis())
Android (Java)
Image
import com.google.mediapipe.framework.image.BitmapImageBuilder; import com.google.mediapipe.framework.image.MPImage; import com.google.mediapipe.tasks.core.BaseOptions; import com.google.mediapipe.tasks.vision.core.RunningMode; import com.google.mediapipe.tasks.vision.facelandmarker.FaceLandmarker; import com.google.mediapipe.tasks.vision.facelandmarker.FaceLandmarkerResult; BaseOptions baseOptions = BaseOptions.builder() .setModelAssetPath("face_landmarker.task") .build(); FaceLandmarker.FaceLandmarkerOptions options = FaceLandmarker.FaceLandmarkerOptions.builder() .setBaseOptions(baseOptions) .setRunningMode(RunningMode.IMAGE) .setNumFaces(1) .setOutputFaceBlendshapes(true) .build(); FaceLandmarker faceLandmarker = FaceLandmarker.createFromOptions(context, options); // Synchronous single-image call (no temporal tracking across calls) MPImage mpImage = new BitmapImageBuilder(bitmap).build(); FaceLandmarkerResult result = faceLandmarker.detect(mpImage);
Video
import com.google.mediapipe.framework.image.BitmapImageBuilder; import com.google.mediapipe.framework.image.MPImage; import com.google.mediapipe.tasks.core.BaseOptions; import com.google.mediapipe.tasks.vision.core.RunningMode; import com.google.mediapipe.tasks.vision.facelandmarker.FaceLandmarker; import com.google.mediapipe.tasks.vision.facelandmarker.FaceLandmarkerResult; BaseOptions baseOptions = BaseOptions.builder() .setModelAssetPath("face_landmarker.task") .build(); FaceLandmarker.FaceLandmarkerOptions options = FaceLandmarker.FaceLandmarkerOptions.builder() .setBaseOptions(baseOptions) .setRunningMode(RunningMode.VIDEO) .setNumFaces(1) .setOutputFaceBlendshapes(true) .build(); FaceLandmarker faceLandmarker = FaceLandmarker.createFromOptions(context, options); // Synchronous: processes every frame in order with monotonic timestamps (no frame drops) MPImage mpImage = new BitmapImageBuilder(frameBitmap).build(); FaceLandmarkerResult result = faceLandmarker.detectForVideo(mpImage, frameTimestampMs);
Livestream
import android.os.SystemClock; import android.util.Log; import com.google.mediapipe.framework.image.BitmapImageBuilder; import com.google.mediapipe.framework.image.MPImage; import com.google.mediapipe.tasks.core.BaseOptions; import com.google.mediapipe.tasks.vision.core.RunningMode; import com.google.mediapipe.tasks.vision.facelandmarker.FaceLandmarker; BaseOptions baseOptions = BaseOptions.builder() .setModelAssetPath("face_landmarker.task") .build(); FaceLandmarker.FaceLandmarkerOptions options = FaceLandmarker.FaceLandmarkerOptions.builder() .setBaseOptions(baseOptions) .setRunningMode(RunningMode.LIVE_STREAM) .setNumFaces(1) .setOutputFaceBlendshapes(true) .setResultListener((result, inputImage) -> { var faces = result.faceLandmarks(); }) .setErrorListener(error -> Log.e("MediaPipe", String.valueOf(error.getMessage()))) .build(); FaceLandmarker faceLandmarker = FaceLandmarker.createFromOptions(context, options); // Async: automatically drops incoming camera frames when busy so results stay current faceLandmarker.detectAsync(mpImage, SystemClock.uptimeMillis());
iOS
Image
import Foundation import MediaPipeTasksVision guard let modelPath = Bundle.main.path(forResource: "face_landmarker", ofType: "task") else { return } let options = FaceLandmarkerOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .image options.numFaces = 1 options.outputFaceBlendshapes = true let faceLandmarker = try FaceLandmarker(options: options) // Synchronous single-image call (stateless across images) let mpImage = try MPImage(uiImage: image) let result = try faceLandmarker.detect(image: mpImage)
Video
import Foundation import MediaPipeTasksVision guard let modelPath = Bundle.main.path(forResource: "face_landmarker", ofType: "task") else { return } let options = FaceLandmarkerOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .video options.numFaces = 1 options.outputFaceBlendshapes = true let faceLandmarker = try FaceLandmarker(options: options) // Synchronous: processes every frame in order with monotonic timestamps (no frame drops) let mpImage = try MPImage(pixelBuffer: pixelBuffer) let result = try faceLandmarker.detect(videoFrame: mpImage, timestampInMilliseconds: timestampMs)
Livestream
import Foundation import MediaPipeTasksVision final class FaceLandmarkerStreamService: NSObject { private var faceLandmarker: FaceLandmarker? func setUp() throws { guard let modelPath = Bundle.main.path(forResource: "face_landmarker", ofType: "task") else { return } let options = FaceLandmarkerOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .liveStream options.numFaces = 1 options.outputFaceBlendshapes = true options.faceLandmarkerLiveStreamDelegate = self faceLandmarker = try FaceLandmarker(options: options) } func detectAsync(mpImage: MPImage, timestampMs: Int) throws { // Async: automatically drops incoming camera frames when busy so results stay current try faceLandmarker?.detectAsync(image: mpImage, timestampInMilliseconds: timestampMs) } } extension FaceLandmarkerStreamService: FaceLandmarkerLiveStreamDelegate { func faceLandmarker( _ faceLandmarker: FaceLandmarker, didFinishDetection result: FaceLandmarkerResult?, timestampInMilliseconds: Int, error: (any Error)? ) { guard let result else { return } DispatchQueue.main.async { let faces = result.faceLandmarks } } }
Python
Image
import mediapipe as mp BaseOptions = mp.tasks.BaseOptions FaceLandmarker = mp.tasks.vision.FaceLandmarker FaceLandmarkerOptions = mp.tasks.vision.FaceLandmarkerOptions VisionRunningMode = mp.tasks.vision.RunningMode options = FaceLandmarkerOptions( base_options=BaseOptions(model_asset_path="face_landmarker.task"), running_mode=VisionRunningMode.IMAGE, num_faces=1, output_face_blendshapes=True, ) with FaceLandmarker.create_from_options(options) as landmarker: # Synchronous single-image call (stateless across images) mp_image = mp.Image.create_from_file("input.jpg") result = landmarker.detect(mp_image)
Video
import mediapipe as mp BaseOptions = mp.tasks.BaseOptions FaceLandmarker = mp.tasks.vision.FaceLandmarker FaceLandmarkerOptions = mp.tasks.vision.FaceLandmarkerOptions VisionRunningMode = mp.tasks.vision.RunningMode options = FaceLandmarkerOptions( base_options=BaseOptions(model_asset_path="face_landmarker.task"), running_mode=VisionRunningMode.VIDEO, num_faces=1, output_face_blendshapes=True, ) with FaceLandmarker.create_from_options(options) as landmarker: # Synchronous: processes every frame in order with monotonic timestamps (no frame drops) for mp_image, timestamp_ms in decoded_video_frames: result = landmarker.detect_for_video(mp_image, timestamp_ms)
Livestream
import mediapipe as mp BaseOptions = mp.tasks.BaseOptions FaceLandmarker = mp.tasks.vision.FaceLandmarker FaceLandmarkerOptions = mp.tasks.vision.FaceLandmarkerOptions VisionRunningMode = mp.tasks.vision.RunningMode def on_result(result, output_image: mp.Image, timestamp_ms: int): print(f"Detected {len(result.face_landmarks)} face(s) at {timestamp_ms} ms") options = FaceLandmarkerOptions( base_options=BaseOptions(model_asset_path="face_landmarker.task"), running_mode=VisionRunningMode.LIVE_STREAM, num_faces=1, output_face_blendshapes=True, result_callback=on_result, ) with FaceLandmarker.create_from_options(options) as landmarker: # Async: automatically drops incoming camera frames when busy so results stay current mp_image = mp.Image(image_format=mp.ImageFormat.SRGB, data=rgb_frame) landmarker.detect_async(mp_image, timestamp_ms)
On Web, you can use DrawingUtils(ctx).drawConnectors(landmarks, FaceLandmarker.FACE_LANDMARKS_TESSELATION) (along with FACE_LANDMARKS_RIGHT_EYE, FACE_LANDMARKS_LEFT_EYE, and FACE_LANDMARKS_FACE_OVAL) from @mediapipe/tasks-vision to render facial mesh overlays on an HTML <canvas>.
Task details
This section describes the capabilities, inputs, outputs, and configuration options of this task.
Features
- Input image processing - Processing includes image rotation, resizing, normalization, and color space conversion.
- Score threshold - Filter results based on prediction scores.
- Still images
- Decoded video frames
- Live video feed
See Prepare vision input data for MPImage, mp.Image, and browser media examples.
- 3D facial surface landmarks (478 points) for each detected face
- 52 facial blendshape scores and 3D facial transformation matrices
Configuration options
This task has the following configuration options:
Web
| Option Name | Description | Value Range | Default Value |
|---|---|---|---|
runningMode |
Sets the running mode for the task:IMAGE: Single image inputs.VIDEO: Decoded video frames and live camera streams. |
{IMAGE, VIDEO} |
IMAGE |
numFaces |
The maximum number of faces detected by the FaceLandmarker. Temporal smoothing is applied when numFaces is set to 1. |
Integer > 0 | 1 |
minFaceDetectionConfidence |
The minimum confidence score for face detection to be considered successful. | Float [0.0, 1.0] |
0.5 |
minFacePresenceConfidence |
The minimum confidence score for face presence in landmark detection. | Float [0.0, 1.0] |
0.5 |
minTrackingConfidence |
The minimum confidence score for face tracking to be considered successful. | Float [0.0, 1.0] |
0.5 |
outputFaceBlendshapes |
Whether Face Landmarker outputs 52 face blendshape scores for driving 3D facial expressions. Note: *Left and *Right blendshapes correspond to the subject's face, not the viewer. Passing a horizontally mirrored image inverts these outputs. |
Boolean |
false |
outputFacialTransformationMatrixes |
Whether FaceLandmarker outputs the 4x4 facial transformation matrix from canonical face coordinates to the detected face. |
Boolean |
false |
Android
| Option Name | Description | Value Range | Default Value |
|---|---|---|---|
runningMode |
Sets the running mode for the task:IMAGE: Single image inputs.VIDEO: Decoded frames of a video.LIVE_STREAM: Livestream of camera input data (requires asynchronous listener/delegate). |
{IMAGE, VIDEO, LIVE_STREAM} |
IMAGE |
numFaces |
The maximum number of faces detected by the FaceLandmarker. Temporal smoothing is applied when numFaces is set to 1. |
Integer > 0 | 1 |
minFaceDetectionConfidence |
The minimum confidence score for face detection to be considered successful. | Float [0.0, 1.0] |
0.5 |
minFacePresenceConfidence |
The minimum confidence score for face presence in landmark detection. | Float [0.0, 1.0] |
0.5 |
minTrackingConfidence |
The minimum confidence score for face tracking to be considered successful. | Float [0.0, 1.0] |
0.5 |
outputFaceBlendshapes |
Whether Face Landmarker outputs 52 face blendshape scores for driving 3D facial expressions. Note: *Left and *Right blendshapes correspond to the subject's face, not the viewer. Passing a horizontally mirrored image inverts these outputs. |
Boolean |
false |
outputFacialTransformationMatrixes |
Whether FaceLandmarker outputs the 4x4 facial transformation matrix from canonical face coordinates to the detected face. |
Boolean |
false |
resultListener |
Asynchronous callback for LIVE_STREAM mode results. |
OutputHandler.ResultListener<FaceLandmarkerResult, MPImage> |
Not set |
errorListener |
Optional error listener for LIVE_STREAM mode. |
ErrorListener |
Not set |
iOS
| Option Name | Description | Value Range | Default Value |
|---|---|---|---|
runningMode |
Sets the running mode for the task:IMAGE: Single image inputs.VIDEO: Decoded frames of a video.LIVE_STREAM: Livestream of camera input data (requires asynchronous listener/delegate). |
{IMAGE, VIDEO, LIVE_STREAM} |
IMAGE |
numFaces |
The maximum number of faces detected by the FaceLandmarker. Temporal smoothing is applied when numFaces is set to 1. |
Integer > 0 | 1 |
minFaceDetectionConfidence |
The minimum confidence score for face detection to be considered successful. | Float [0.0, 1.0] |
0.5 |
minFacePresenceConfidence |
The minimum confidence score for face presence in landmark detection. | Float [0.0, 1.0] |
0.5 |
minTrackingConfidence |
The minimum confidence score for face tracking to be considered successful. | Float [0.0, 1.0] |
0.5 |
outputFaceBlendshapes |
Whether Face Landmarker outputs 52 face blendshape scores for driving 3D facial expressions. Note: *Left and *Right blendshapes correspond to the subject's face, not the viewer. Passing a horizontally mirrored image inverts these outputs. |
Boolean |
false |
outputFacialTransformationMatrixes |
Whether FaceLandmarker outputs the 4x4 facial transformation matrix from canonical face coordinates to the detected face. |
Boolean |
false |
faceLandmarkerLiveStreamDelegate |
Asynchronous delegate for LIVE_STREAM mode results (invoked on a serial background queue). |
FaceLandmarkerLiveStreamDelegate |
Not set |
Python
| Option Name | Description | Value Range | Default Value |
|---|---|---|---|
running_mode |
Sets the running mode for the task:IMAGE: Single image inputs.VIDEO: Decoded frames of a video.LIVE_STREAM: Livestream of camera input data (requires result_callback). |
{IMAGE, VIDEO, LIVE_STREAM} |
IMAGE |
num_faces |
The maximum number of faces detected by the FaceLandmarker. Temporal smoothing is applied when numFaces is set to 1. |
Integer > 0 | 1 |
min_face_detection_confidence |
The minimum confidence score for face detection to be considered successful. | Float [0.0, 1.0] |
0.5 |
min_face_presence_confidence |
The minimum confidence score for face presence in landmark detection. | Float [0.0, 1.0] |
0.5 |
min_tracking_confidence |
The minimum confidence score for face tracking to be considered successful. | Float [0.0, 1.0] |
0.5 |
output_face_blendshapes |
Whether Face Landmarker outputs 52 face blendshape scores for driving 3D facial expressions. Note: *Left and *Right blendshapes correspond to the subject's face, not the viewer. Passing a horizontally mirrored image inverts these outputs. |
Boolean |
False |
output_facial_transformation_matrixes |
Whether FaceLandmarker outputs the 4x4 facial transformation matrix from canonical face coordinates to the detected face. |
Boolean |
False |
result_callback |
Asynchronous callback function for LIVE_STREAM mode results. |
Callable |
Not set |
Task output
Each FaceLandmarkerResult returns 3D facial mesh landmarks, optional expression blendshape coefficients, and optional 4x4 transformation matrices for each detected face:
| Field | Type / Coordinate Space | Description |
|---|---|---|
faceLandmarks |
NormalizedLandmark[][] (x, y in [0.0, 1.0]) |
478 3D facial landmarks per face normalized by image width and height, with z depth scaled like x relative to the center of the head (face_landmarks in Python). |
faceBlendshapes |
Classifications[] (score in [0.0, 1.0]) |
52 facial expression coefficients (browDownLeft, jawOpen, eyeBlinkRight, etc.) when outputFaceBlendshapes is enabled (face_blendshapes in Python). Note: *Left and *Right correspond to the subject's face; mirroring the input image inverts them. |
facialTransformationMatrixes |
Matrix[] (4×4 float matrix) |
Optional 3D canonical-to-observed face pose transformation matrix when outputFacialTransformationMatrixes is enabled (facial_transformation_matrixes in Python). |
Example FaceLandmarkerResult payload
The following example shows the output for a single detected face with blendshapes and the 4x4 pose matrix enabled:
{
faceLandmarks: [
[
{ x: 0.5971, y: 0.4854, z: -0.0384 }, // #0 upper lip center (normalized [0.0, 1.0])
{ x: 0.3303, y: 0.2929, z: -0.0949 }, // #1 nose tip
// ... 478 normalized 3D landmarks per detected face (#0..#477)
]
],
faceBlendshapes: [
{
categories: [
{ categoryName: "browDownLeft", score: 0.8297 },
{ categoryName: "browDownRight", score: 0.8097 },
{ categoryName: "browInnerUp", score: 0.0004 },
// ... 52 blendshape coefficients in [0.0, 1.0]
]
}
],
facialTransformationMatrixes: [
[
[0.9992, -0.0123, 0.0391, -0.3708],
[0.0166, 0.9935, -0.1128, 22.7720],
[-0.0375, 0.1133, 0.9928, -65.1204],
[0.0, 0.0, 0.0, 1.0]
]
]
}
Models
The Face Landmarker uses a series of models to predict face landmarks. The first model detects faces, a second model locates landmarks on the detected faces, and a third model uses those landmarks to identify facial features and expressions.
The following models are packaged together into a downloadable model bundle:
- Face detection model: detects the presence of faces with a few key facial landmarks.
- Face landmark model: adds a complete 3D mapping of the face. The model outputs an estimate of 478 3-dimensional face landmarks.
- Blendshape prediction model: receives output from the face landmark model and predicts 52 blendshape scores representing facial expressions.
The face detection model is the BlazeFace short-range model, a lightweight and accurate face detector optimized for mobile GPU inference. For more information, see the Face Detector task.
The image below shows a complete mapping of facial landmarks from the model bundle output.

478 3D facial mesh landmarks
For a more detailed view of the face landmarks, see the full-size image.
| Model bundle | Input shape | Data type | Model Cards | Versions |
|---|---|---|---|---|
| FaceLandmarker | FaceDetector: 192 x 192 FaceLandmarker-V2: 256 x 256 Blendshape: 1 x 146 x 2 |
float 16 |
FaceDetector FaceLandmarker-V2 Blendshape |
Latest |
