Generate thumbnail tracks for scrubbing

View Markdown

Scrub previews let viewers see where they’re seeking before they release the slider. “Reel” (a media platform like Vimeo) generates thumbnail images at regular intervals and maps them to the player’s seek bar.

API

Extract a frame every 5 seconds from the source video:

ittybit image \
  -i https://reel-app.com/videos/keynote-2025.mp4 \
  --interval 5 \
  --width 160 \
  --format jpg
const task = {
  input: 'https://reel-app.com/videos/keynote-2025.mp4',
  kind: 'image',
  options: {
    interval: 5,
    width: 160,
    format: 'jpg',
  },
};

const res = await fetch('https://api.ittybit.com/jobs', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.ITTYBIT_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(task),
});
const data = await res.json();
import requests

task = {
    "input": "https://reel-app.com/videos/keynote-2025.mp4",
    "kind": "image",
    "options": {
        "interval": 5,
        "width": 160,
        "format": "jpg",
    },
}

res = requests.post(
    "https://api.ittybit.com/jobs",
    headers={"Authorization": f"Bearer {api_key}"},
    json=task,
)
data = res.json()
TASK='{
  "input": "https://reel-app.com/videos/keynote-2025.mp4",
  "kind": "image",
  "options": {
    "interval": 5,
    "width": 160,
    "format": "jpg"
  }
}'

curl -X POST https://api.ittybit.com/jobs \
  -H "Authorization: Bearer $ITTYBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d "$TASK"

The interval option generates one frame every N seconds across the full duration. A 10-minute video at interval: 5 produces 120 thumbnail images.

CLI

ittybit image \
  -i keynote-2025.mp4 \
  -o thumbs/ \
  --interval 5 \
  --width 160 \
  --format jpg

Output files are named sequentially (thumb-000.jpg, thumb-001.jpg, etc.).

Choosing the interval

Video durationIntervalApproximate frames
< 5 min2s~150
5-30 min5s~60-360
30-120 min10s~180-720
> 2 hours15-30sVaries

Shorter intervals give smoother scrubbing but produce more images. 160px wide JPEGs are typically 3-5 KB each, so even 500 frames adds under 2.5 MB total.

Generating a VTT thumbnail manifest

Most players (Video.js, Plyr, hls.js) use a WebVTT file to map timestamps to thumbnail URLs:

WEBVTT

00:00:00.000 --> 00:00:05.000
https://cdn.reel-app.com/thumbs/keynote-2025/thumb-000.jpg

00:00:05.000 --> 00:00:10.000
https://cdn.reel-app.com/thumbs/keynote-2025/thumb-001.jpg

00:00:10.000 --> 00:00:15.000
https://cdn.reel-app.com/thumbs/keynote-2025/thumb-002.jpg

Point your player’s thumbnail track at this VTT file and scrub previews work automatically.

Sprite sheets vs individual frames

ApproachProsCons
Individual framesSimple, cache-friendlyMore HTTP requests
Sprite sheetSingle requestLarger initial download, needs coordinates

For most cases, individual frames served from a CDN with HTTP/2 are the simpler choice.