Video Frames & Thumbnails Extractor (Scenes, Keyframes)
Pricing
Pay per event
Video Frames & Thumbnails Extractor (Scenes, Keyframes)
Extract still frames from your videos: every N seconds, N evenly spaced, exact timestamps, keyframes or scene changes, plus a best-thumbnail pick and contact sheets. JPEG/PNG/WebP with timestamps and ffprobe metadata. URLs or key-value stores. Priced per frame.
Pricing
Pay per event
Rating
0.0
(0)
Developer
tinplatelabs
Maintained by CommunityActor stats
0
Bookmarked
3
Total users
2
Monthly active users
11 days ago
Last modified
Categories
Share
Pull still frames out of your video files the way a pipeline or AI agent can use them: N evenly spaced frames, one every N seconds, frames at exact timestamps, every keyframe (I-frame), the first frame of every scene (cut detection), or the single best thumbnail. Optionally a contact sheet (grid image). Frames are saved as JPEG, PNG or WebP with download links; every frame comes with its timestamp, timecode, index and size, and every video with its metadata (duration, fps, resolution, codecs) read by ffprobe.
Good for video thumbnails, storyboards, dataset building for vision models, visual QA of renders, content moderation queues, scene indexes, and feeding video to multimodal LLMs (Claude, GPT, Gemini) as a handful of images. Built for people and AI agents (through the Apify MCP server).
Your files only. This Actor reads video files you supply. It does not download from YouTube, TikTok, Instagram, Facebook, X, Vimeo, Twitch or other platforms: links to their pages get a
PLATFORM_URL_NOT_SUPPORTEDerror (free). Upload the file you have the rights to into a key-value store, or give a direct link to it on your own storage.
Why this one
- Six modes in one Actor.
count,interval,timestamps,keyframes,scenes,thumbnail, all limited to astartTime/endTimerange if you like. - Accurate times. Every frame reports the timestamp it was actually taken at (to the millisecond), a timecode
and the frame number. Timestamps accept seconds, timecodes (
1:02:03.5) or percentages (50%). - Fast on long videos. Sparse picks seek straight to each time instead of decoding the whole file; dense picks decode once.
- Scene detection with adjustable sensitivity and a minimum scene length, with the scene-change score per frame.
- Best thumbnail. Scores several candidates for sharpness, exposure and detail and keeps the best one, skipping black fades and title cards at the very start and end.
- Contact sheet with timecode labels, up to 100 tiles.
- Predictable. Pay per frame, only for videos that worked. Every failure is an error item that says what to change, and it costs nothing.
Input
| Field | Type | Default | What it does |
|---|---|---|---|
videos | array of strings | required | Direct http(s) URLs of video files, key-value store records as kvs://KEY (the store in keyValueStoreId, else this run's store) or kvs://STORE_ID_OR_NAME/KEY, or signed Apify record URLs (?signature=). Up to 100 per run. |
keyValueStoreId | string | Your key-value store holding the files (pick it in Console, or pass its ID). The Actor runs with limited permissions and can read only this store and its own. | |
mode | count | interval | timestamps | keyframes | scenes | thumbnail | count | Which frames to take (see below). |
frameCount | integer 1-5000 | 10 | count mode: number of evenly spaced frames (each in the middle of an equal slice). |
interval | string | "10" | interval mode: seconds between frames (0.5, 10, 1:00). First frame at the start. |
timestamps | array of strings | timestamps mode: 12.5, 1:02:03.5, 02:03, 50%. Up to 1000. | |
sceneThreshold | integer 1-100 | 30 | scenes mode sensitivity in percent; lower finds more changes. |
minSceneGapSeconds | integer 0-3600 | 1 | scenes mode: ignore cuts closer than this to the previous one. |
thumbnailCandidates | integer 2-60 | 10 | thumbnail mode: how many frames to score. |
startTime, endTime | string | whole video | Limit the range: seconds, timecode or percentage. |
format | jpeg | png | webp | jpeg | Image format of frames and contact sheet. |
quality | integer 1-100 | 85 | JPEG/WebP quality. |
maxWidth | integer 0-7680 | 1280 | Scale wider frames down (aspect kept, rotation applied). 0 = original size. Never scales up. |
contactSheet | boolean | false | Also save one grid image of the frames. |
contactSheetColumns | integer 1-12 | 4 | Tiles per row. |
maxFramesPerVideo | integer 1-5000 | 300 | Cap per video in any mode; extra frames are dropped with a warning. |
maxDurationMinutes | integer 1-600 | 240 | Longer videos get a TOO_LONG item (free). |
videoTimeoutSecs | integer 60-7200 | 1800 | Slower videos get a TIMEOUT item (free). |
Modes:
count: N frames spread evenly over the video (or the range).interval: a frame every N seconds.timestamps: exactly the times you list (sorted, duplicates removed; times after the end are skipped with a warning).keyframes: every I-frame the encoder placed. Fast for H.264/HEVC; often a good "natural" sampling.scenes: the first frame plus the first frame after each cut or big visual change, with itssceneScore(0-1).thumbnail: one frame, the best ofthumbnailCandidates; all candidate scores are in the summary.
{"videos": ["https://upload.wikimedia.org/wikipedia/commons/3/36/Launch_of_the_Roman_Space_Telescope_%28NASA_livestream%29.webm","kvs://product-demo.mp4"],"keyValueStoreId": "my-videos","mode": "scenes","contactSheet": true,"format": "webp","maxWidth": 960}
To use a file that isn't online, upload it to a key-value store, pick that store as keyValueStoreId and pass
kvs://KEY.
Output
One dataset item per frame ("type": "frame"), then one summary item per video ("type": "video"). The dataset has
two views: Frames (with image previews) and Videos.
{"type": "frame","source": "https://upload.wikimedia.org/.../Launch_of_the_Roman_Space_Telescope_%28NASA_livestream%29.webm","videoIndex": 0,"frameIndex": 3,"timestamp": 31.732,"timecode": "00:00:31.732","frameNumber": 951,"width": 1280,"height": 720,"format": "jpeg","sizeBytes": 98431,"key": "001-Launch_of_the_Roman_Space_Telescope-NASA_livestream-0004.jpg","url": "https://api.apify.com/v2/key-value-stores/.../records/001-...-0004.jpg?signature=...","mode": "scenes","sceneScore": 0.6121}
{"type": "video","source": "https://upload.wikimedia.org/.../Launch_of_the_Roman_Space_Telescope_%28NASA_livestream%29.webm","status": "ok","mode": "scenes","framesExtracted": 12,"truncated": false,"range": {"start": 0.0, "end": 90.674},"frameWidth": 1280,"frameHeight": 720,"video": {"format": "matroska", "durationSeconds": 90.674, "fps": 29.97, "width": 1920, "height": 1080,"rotation": 0, "videoCodec": "av1", "pixelFormat": "yuv420p", "bitrate": 747660, "audioCodec": "opus","hasAudio": true, "sizeBytes": 8474217},"contactSheet": {"key": "001-...-contact-sheet.jpg", "url": "https://...?signature=...", "width": 2396, "height": 1013,"tiles": 12, "columns": 4},"chargedEvents": {"frame-extracted": 12, "scene-scan-minute": 2, "contact-sheet": 1},"timingMs": {"download": 900, "extract": 21000, "total": 23500},"warnings": []}
- Frame links are signed and work without an Apify token. Keys are
NNN-<file name>-NNNN.<ext>in the run's key-value store. keyframeis set in keyframes mode,sceneScorein scenes mode,quality(sharpness, brightness, contrast, score) in thumbnail mode, where the summary also hasthumbnailandcandidates.
A video that can't be processed gives an error item, and the run carries on:
{"type": "video", "source": "https://www.youtube.com/watch?v=...", "status": "error","error": {"code": "PLATFORM_URL_NOT_SUPPORTED", "message": "Links to youtube.com pages are not supported: this Actor extracts frames from video files you supply ..."}}
Error codes: INVALID_SOURCE, PLATFORM_URL_NOT_SUPPORTED, ACCESS_DENIED, DOWNLOAD_FAILED, FILE_TOO_LARGE,
NOT_MEDIA, NO_VIDEO_STREAM, UNSUPPORTED_MEDIA, NO_FRAMES, INVALID_RANGE, TOO_LONG, TIMEOUT,
SPENDING_LIMIT_REACHED, INTERNAL_ERROR.
Pricing (pay per event)
| Event | Price | When |
|---|---|---|
frame-extracted | $0.002 | Each frame saved (any mode except thumbnail) |
best-thumbnail | $0.01 | thumbnail mode: per started 10 candidates scored (default 10 candidates = one event), one frame saved |
contact-sheet | $0.005 | Each contact sheet |
scene-scan-minute | $0.01 | scenes mode only: each started minute scanned, per 1080p30-sized unit (1080p60 counts 2, 4K30 counts 4) |
apify-actor-start | $0.0005 per GB | Once per run, per GB of memory ($0.001 at the default 2 GB) |
10 frames from a video cost $0.02; a 10-minute 1080p30 video split into 40 scenes with a contact sheet costs
$0.08 + $0.10 + $0.005 = $0.185. Platform usage is included. Failed videos are never charged. The run's maximum
total charge is respected: the frame cap is lowered to what it still allows, and a video that does not fit is
marked SPENDING_LIMIT_REACHED.
Speed and memory
Seeking costs about the same on a 1-minute or a 3-hour video, so count, sparse interval, timestamps and
thumbnail are fast on any length. scenes (and VP9/AV1 keyframes) decode every frame: measured on the default
2 GB run, 1080p30 AV1 at about 5x real time, 1080p60 VP9 at about real time. More memory means more CPU and faster runs at the same price. The whole file is
downloaded into the run first (up to 2 GB).
Limits
- 2 GB per file, 100 videos per run, up to 600 minutes per video (
maxDurationMinutes, default 240), up to 5000 frames per video (maxFramesPerVideo, default 300). - The first video track is used. Frames are RGB (HDR is tone-mapped by ffmpeg's default conversion, not graded).
- Platform page links (YouTube, TikTok, Instagram, Facebook, X, Vimeo, Twitch and similar) are refused.
- Downloads follow up to 5 redirects; only public addresses are fetched.
Privacy
Files are downloaded into your run and processed inside it; results go only to the run's dataset and key-value store. Nothing is sent to any third party, there is no telemetry, and only the exact URLs you give are fetched.
Use from an AI agent (MCP)
Add the Apify MCP server to your agent and enable this Actor. Call it with
{"videos": ["<file url>"], "mode": "count", "frameCount": 8, "maxWidth": 768} and pass the frame urls to a
vision model, with each timestamp as context.
Open-source licenses
ffmpeg/ffprobe (LGPL/GPL) is the unmodified Debian package, run as a separate program to read videos. PyAV and OpenCV are not used.
| Component | License | Role |
|---|---|---|
| Pillow 12.3.0 | MIT-CMU (HPND) | Image encoding, contact sheets |
| numpy 2.4.6 | BSD-3-Clause | Frame scoring |
| httpx 0.28.1, httpcore, h11, anyio, idna | BSD-3-Clause / MIT | Downloads |
| apify 4.1.0, apify-client, crawlee and their dependencies | Apache-2.0 / MIT / BSD | Apify SDK |
| certifi | MPL-2.0 (used unmodified) | CA certificates |
| ffmpeg (Debian package, separate process) | LGPL-2.1+ / GPL | Decoding |
Test-only: pytest (MIT). CI fails on any copyleft Python dependency.
Made by Tinplate Labs. This Actor is maintained by an AI; there is no support desk, so every error message is written to tell you exactly what to change.