Sample, score, and rank the best thumbnail frames from a Mux video asset using the Mux Robots API.
Experimental
The find-best-thumbnails workflow is experimental. The API shape, parameters, behavior, and pricing may change. If we make changes to this workflow while you're using it, we'll let you know via email.
Find the strongest thumbnail frames in a video. Mux samples frames across a Mux asset, scores each one for thumbnail quality, and returns the top candidates ranked best to worst with per-category subscores and a short description of each frame. It's useful for auto-selecting a poster image, building a thumbnail picker, or A/B testing thumbnail options. See the Find Best Thumbnails API referenceAPI for the full endpoint specification. See Mux Robots pricing for unit costs.
Find best thumbnails requires a video asset in the ready state. Audio-only assets are not supported, since the workflow scores sampled video frames.
find-best-thumbnails jobcurl https://api.mux.com/robots/v0/jobs/find-best-thumbnails \
-H "Content-Type: application/json" \
-X POST \
-d '{
"parameters": {
"asset_id": "YOUR_ASSET_ID",
"max_thumbnails": 3
}
}' \
-u ${MUX_TOKEN_ID}:${MUX_TOKEN_SECRET}This request is asynchronous. The POST returns immediately with the job in pending status and does not include results. We strongly recommend listening for the robots.job.find_best_thumbnails.completed webhook. The payload contains the full completed job, so no follow-up API call is needed. If webhooks aren't an option, you can poll GET /robots/v0/jobs/find-best-thumbnails/{JOB_ID} with the id from the response until the status is completed.
| Parameter | Type | Description |
|---|---|---|
asset_id | string | Required. The Mux asset ID of the video asset to pull thumbnail candidates from. |
max_thumbnails | integer | Optional. Maximum number of candidate thumbnails to return, from 1 to 5. Defaults to 1. |
output_steering | object | Optional. Curated controls that guide how candidates are scored without changing the response schema. See Output steering. |
Use output_steering when you want best-effort control over which frames score highest. These fields guide the workflow but do not guarantee exact output.
| Field | Type | Description |
|---|---|---|
selection_strategy | string | Preferred kind of thumbnail candidate to favor. Supported values: face_or_action, clean_composition, high_contrast, brand_safe, and campaign_thumbnail. |
looking_for | string | Open-ended description of what you're explicitly looking for in candidate thumbnails. |
audience | string | Intended audience used to guide scoring. |
brand_terms | array of strings | Preferred brand or domain terms to use when supported by the frame. |
campaign_style | string | Short description of the campaign or channel thumbnail style to prefer when supported by the frame. |
scoring_priorities | array of strings | Rubric criteria to emphasize in close calls. |
{
"parameters": {
"asset_id": "YOUR_ASSET_ID",
"max_thumbnails": 5,
"output_steering": {
"selection_strategy": "face_or_action",
"looking_for": "a clear shot of the host mid-demo with the product visible",
"audience": "developers evaluating a video API",
"brand_terms": ["Mux"],
"campaign_style": "clean, high-contrast tech explainer",
"scoring_priorities": ["sharp focus", "readable at small sizes"]
}
}
}The outputs object is included in the job once its status is completed. You'll receive it on the robots.job.find_best_thumbnails.completed webhook (recommended), or you can fetch it with GET /robots/v0/jobs/find-best-thumbnails/{JOB_ID}. It contains:
| Field | Type | Description |
|---|---|---|
best_thumbnails | array | Selected candidate thumbnails, ordered best to worst by overall quality score. |
best_thumbnails[].timestamp_ms | number | Frame timestamp in milliseconds. |
best_thumbnails[].overall | number | Overall quality score from 0 to 1. |
best_thumbnails[].description | string | AI-generated description of the frame content. |
best_thumbnails[].subscores | object | Per-category quality scores, each from 0 to 1. |
best_thumbnails[].subscores.focus | number | Sharpness and focus quality. |
best_thumbnails[].subscores.face_or_action | number | Presence of faces or dynamic action. |
best_thumbnails[].subscores.composition | number | Visual composition and framing quality. |
best_thumbnails[].subscores.contrast_color | number | Color contrast and vibrancy. |
best_thumbnails[].subscores.brand_fit | number | Alignment with brand guidelines. |
Each candidate is identified by its timestamp_ms. To render the frame as an image, convert the timestamp to seconds and pass it to the image API: https://image.mux.com/{PLAYBACK_ID}/thumbnail.jpg?time={SECONDS}.
This is the payload delivered to the robots.job.find_best_thumbnails.completed webhook, and the same shape you get from GET /robots/v0/jobs/find-best-thumbnails/{JOB_ID}:
{
"data": {
"id": "rjob_thumb123",
"workflow": "find-best-thumbnails",
"status": "completed",
"units_consumed": 3500,
"parameters": {
"asset_id": "YOUR_ASSET_ID",
"max_thumbnails": 3
},
"outputs": {
"best_thumbnails": [
{
"timestamp_ms": 42000,
"overall": 0.91,
"description": "The host faces the camera mid-sentence with the product dashboard sharp behind them.",
"subscores": {
"focus": 0.95,
"face_or_action": 0.92,
"composition": 0.88,
"contrast_color": 0.86,
"brand_fit": 0.9
}
},
{
"timestamp_ms": 118500,
"overall": 0.78,
"description": "A wide shot of the upload screen with the cursor on the upload button.",
"subscores": {
"focus": 0.82,
"face_or_action": 0.6,
"composition": 0.85,
"contrast_color": 0.8,
"brand_fit": 0.83
}
}
]
}
}
}