MediaPipe Tasks Live ML anywhere
Run vision, text, audio, retrieval, and decision models directly in your app across Web, Android, iOS, and Python with on-device CPU and GPU acceleration.
- Web, Android, iOS & Python
- CPU & GPU acceleration
- On-device inference
Consistent API across platforms
Build once with matching task options and result types across JavaScript, Kotlin/Java, Swift, and Python.
Hardware-accelerated pipelines
Each task bundles preprocessing, LiteRT model execution, and postprocessing on CPU or GPU.
Real-time streaming modes
Process single images, decoded video files, or live camera and audio streams with low-latency on-device execution.
Explore the tasks
22 on-device tasks across five categories. Pick a category to filter, or browse them all.
Audio
3 tasksClassify sounds, transcribe speech, and synthesize voice on-device.
Decision
1 taskScore choices and rubrics on-device.
Retrieval
2 tasksEmbed and search text and images for on-device RAG.
Text
5 tasksClassify, detect languages, embed, proofread, and summarize text.
Vision
11 tasksDetect, track, segment, and classify in images, video, and camera streams.
Quickstart
Install, configure, and run — the same three steps on every platform.
- 1
Install the SDK
Add the domain package from npm, Maven Central, Swift Package Manager, or PyPI.
- 2
Configure the task
Point
baseOptionsat a model file and choose a running mode and hardware delegate. - 3
Run inference
Prepare input data—images, video frames, live camera streams, text, or audio—and run inference.
Web
Image
import { FilesetResolver, HandLandmarker } from "@mediapipe/tasks-vision"; const vision = await FilesetResolver.forVisionTasks( "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm" ); const handLandmarker = await HandLandmarker.createFromOptions(vision, { baseOptions: { modelAssetPath: "hand_landmarker.task", delegate: "GPU" }, runningMode: "IMAGE", numHands: 2, }); // Synchronous single-frame call (stateless across images) const image = document.getElementById("image") as HTMLImageElement; const result = handLandmarker.detect(image);
Video
import { FilesetResolver, HandLandmarker } from "@mediapipe/tasks-vision"; const vision = await FilesetResolver.forVisionTasks( "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm" ); const handLandmarker = await HandLandmarker.createFromOptions(vision, { baseOptions: { modelAssetPath: "hand_landmarker.task", delegate: "GPU" }, runningMode: "VIDEO", numHands: 2, }); // Synchronous across decoded frames with monotonic timestamps (never drops frames) for (const { frame, timestampMs } of decodedVideoFrames) { const result = handLandmarker.detectForVideo(frame, timestampMs); }
Livestream
import { FilesetResolver, HandLandmarker } 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 handLandmarker = await HandLandmarker.createFromOptions(vision, { baseOptions: { modelAssetPath: "hand_landmarker.task", delegate: "GPU" }, runningMode: "VIDEO", numHands: 2, }); 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 = handLandmarker.detectForVideo(video, performance.now()); console.log(result.landmarks, result.handedness); } 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.handlandmarker.HandLandmarker val baseOptions = BaseOptions.builder() .setModelAssetPath("hand_landmarker.task") .build() val options = HandLandmarker.HandLandmarkerOptions.builder() .setBaseOptions(baseOptions) .setRunningMode(RunningMode.IMAGE) .setNumHands(2) .build() val handLandmarker = HandLandmarker.createFromOptions(context, options) // Synchronous single-image call (no temporal tracking across calls) val mpImage = BitmapImageBuilder(bitmap).build() val result = handLandmarker.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.handlandmarker.HandLandmarker val baseOptions = BaseOptions.builder() .setModelAssetPath("hand_landmarker.task") .build() val options = HandLandmarker.HandLandmarkerOptions.builder() .setBaseOptions(baseOptions) .setRunningMode(RunningMode.VIDEO) .setNumHands(2) .build() val handLandmarker = HandLandmarker.createFromOptions(context, options) // Synchronous: processes every frame in order with monotonic timestamps (no frame drops) val mpImage = BitmapImageBuilder(frameBitmap).build() val result = handLandmarker.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.handlandmarker.HandLandmarker val baseOptions = BaseOptions.builder() .setModelAssetPath("hand_landmarker.task") .build() val options = HandLandmarker.HandLandmarkerOptions.builder() .setBaseOptions(baseOptions) .setRunningMode(RunningMode.LIVE_STREAM) .setNumHands(2) .setResultListener { result, _ -> val hands = result.landmarks() } .setErrorListener { error -> Log.e("MediaPipe", error.message.orEmpty()) } .build() val handLandmarker = HandLandmarker.createFromOptions(context, options) // Async: automatically drops incoming camera frames when busy so results stay current handLandmarker.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.handlandmarker.HandLandmarker; import com.google.mediapipe.tasks.vision.handlandmarker.HandLandmarkerResult; BaseOptions baseOptions = BaseOptions.builder() .setModelAssetPath("hand_landmarker.task") .build(); HandLandmarker.HandLandmarkerOptions options = HandLandmarker.HandLandmarkerOptions.builder() .setBaseOptions(baseOptions) .setRunningMode(RunningMode.IMAGE) .setNumHands(2) .build(); HandLandmarker handLandmarker = HandLandmarker.createFromOptions(context, options); // Synchronous single-image call (no temporal tracking across calls) MPImage mpImage = new BitmapImageBuilder(bitmap).build(); HandLandmarkerResult result = handLandmarker.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.handlandmarker.HandLandmarker; import com.google.mediapipe.tasks.vision.handlandmarker.HandLandmarkerResult; BaseOptions baseOptions = BaseOptions.builder() .setModelAssetPath("hand_landmarker.task") .build(); HandLandmarker.HandLandmarkerOptions options = HandLandmarker.HandLandmarkerOptions.builder() .setBaseOptions(baseOptions) .setRunningMode(RunningMode.VIDEO) .setNumHands(2) .build(); HandLandmarker handLandmarker = HandLandmarker.createFromOptions(context, options); // Synchronous: processes every frame in order with monotonic timestamps (no frame drops) MPImage mpImage = new BitmapImageBuilder(frameBitmap).build(); HandLandmarkerResult result = handLandmarker.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.handlandmarker.HandLandmarker; BaseOptions baseOptions = BaseOptions.builder() .setModelAssetPath("hand_landmarker.task") .build(); HandLandmarker.HandLandmarkerOptions options = HandLandmarker.HandLandmarkerOptions.builder() .setBaseOptions(baseOptions) .setRunningMode(RunningMode.LIVE_STREAM) .setNumHands(2) .setResultListener((result, inputImage) -> { var hands = result.landmarks(); }) .setErrorListener(error -> Log.e("MediaPipe", String.valueOf(error.getMessage()))) .build(); HandLandmarker handLandmarker = HandLandmarker.createFromOptions(context, options); // Async: automatically drops incoming camera frames when busy so results stay current handLandmarker.detectAsync(mpImage, SystemClock.uptimeMillis());
iOS
Image
import Foundation import MediaPipeTasksVision guard let modelPath = Bundle.main.path(forResource: "hand_landmarker", ofType: "task") else { return } let options = HandLandmarkerOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .image options.numHands = 2 let handLandmarker = try HandLandmarker(options: options) // Synchronous single-image call (stateless across images) let mpImage = try MPImage(uiImage: image) let result = try handLandmarker.detect(image: mpImage)
Video
import Foundation import MediaPipeTasksVision guard let modelPath = Bundle.main.path(forResource: "hand_landmarker", ofType: "task") else { return } let options = HandLandmarkerOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .video options.numHands = 2 let handLandmarker = try HandLandmarker(options: options) // Synchronous: processes every frame in order with monotonic timestamps (no frame drops) let mpImage = try MPImage(pixelBuffer: pixelBuffer) let result = try handLandmarker.detect(videoFrame: mpImage, timestampInMilliseconds: timestampMs)
Livestream
import Foundation import MediaPipeTasksVision final class HandLandmarkerStreamService: NSObject { private var handLandmarker: HandLandmarker? func setUp() throws { guard let modelPath = Bundle.main.path(forResource: "hand_landmarker", ofType: "task") else { return } let options = HandLandmarkerOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .liveStream options.numHands = 2 options.handLandmarkerLiveStreamDelegate = self handLandmarker = try HandLandmarker(options: options) } func detectAsync(mpImage: MPImage, timestampMs: Int) throws { // Async: automatically drops incoming camera frames when busy so results stay current try handLandmarker?.detectAsync(image: mpImage, timestampInMilliseconds: timestampMs) } } extension HandLandmarkerStreamService: HandLandmarkerLiveStreamDelegate { func handLandmarker( _ handLandmarker: HandLandmarker, didFinishDetection result: HandLandmarkerResult?, timestampInMilliseconds: Int, error: (any Error)? ) { guard let result else { return } DispatchQueue.main.async { let hands = result.landmarks } } }
Python
Image
import mediapipe as mp BaseOptions = mp.tasks.BaseOptions HandLandmarker = mp.tasks.vision.HandLandmarker HandLandmarkerOptions = mp.tasks.vision.HandLandmarkerOptions VisionRunningMode = mp.tasks.vision.RunningMode options = HandLandmarkerOptions( base_options=BaseOptions(model_asset_path="hand_landmarker.task"), running_mode=VisionRunningMode.IMAGE, num_hands=2, ) with HandLandmarker.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 HandLandmarker = mp.tasks.vision.HandLandmarker HandLandmarkerOptions = mp.tasks.vision.HandLandmarkerOptions VisionRunningMode = mp.tasks.vision.RunningMode options = HandLandmarkerOptions( base_options=BaseOptions(model_asset_path="hand_landmarker.task"), running_mode=VisionRunningMode.VIDEO, num_hands=2, ) with HandLandmarker.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 HandLandmarker = mp.tasks.vision.HandLandmarker HandLandmarkerOptions = mp.tasks.vision.HandLandmarkerOptions VisionRunningMode = mp.tasks.vision.RunningMode def on_result(result, output_image: mp.Image, timestamp_ms: int): print(f"Detected {len(result.hand_landmarks)} hand(s) at {timestamp_ms} ms") options = HandLandmarkerOptions( base_options=BaseOptions(model_asset_path="hand_landmarker.task"), running_mode=VisionRunningMode.LIVE_STREAM, num_hands=2, result_callback=on_result, ) with HandLandmarker.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)










