Video Frame Extractor: Stills Every N Seconds or at Set Times
Pricing
from $1.00 / 1,000 frames
Video Frame Extractor: Stills Every N Seconds or at Set Times
Extract frames from video links (MP4, WebM, MOV, MKV, HLS .m3u8): evenly spaced video frames, one every N seconds, or at exact times, as JPG, PNG or WebP stills with public links, plus length, fps and codec. Pay per frame.
Pricing
from $1.00 / 1,000 frames
Rating
0.0
(0)
Developer
DTK Foundry
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
5 hours ago
Last modified
Categories
Share
Extract still frames from any direct video link (MP4, WebM, MOV, MKV, AVI, HLS .m3u8 and most other formats
ffmpeg reads): a set number of evenly spaced frames, one every N seconds, or frames at the exact times you
list. Each frame comes back as a JPG, PNG or WebP image with a public link, ready for AI vision models,
thumbnails, contact sheets or datasets, together with the video's length, size, frame rate and codec.
- Reliable. Tested on 200 varied extractions (all three modes, JPG/PNG/WebP, scaling, contact sheets) over 96 public videos from 9 hosts (test-video sites, NASA, the Internet Archive, Wikimedia Commons, HLS streams from Apple, Mux and Unified Streaming): 195 delivered every frame asked for and no video failed to open. The 5 short ones were Wikimedia Commons limiting downloads and one dropped download on the Internet Archive; 1,012 of 1,042 frames in all.
- Only the frames you need are downloaded. Each frame is taken with a seek, so a frame from minute 40 of a 2 GB file costs a few megabytes, not the whole file.
- Exact times. Frames are decoded at the time you ask for, not snapped to the nearest keyframe.
- HLS done right. For a master playlist one video variant is read (the smallest at least
maxWidthwide, else the largest up to 1080p), and fragmented-MP4 HLS streams, which ffmpeg cannot seek, are read segment by segment. - Three ways to choose frames: evenly spaced (the black first frame is skipped), every N seconds within an
optional start/end window, or a list of times like
1:35or0:01:35.5. - Free contact sheet of each video's frames on request.
- Pay per frame delivered. Videos that cannot be read and frames that fail are never charged.
Input
| Field | Type | Default | Description |
|---|---|---|---|
videoUrls | array | [] | Direct links to video files, one per line. Up to 500 per run. Empty = a free format example. |
mode | string | count | count (evenly spaced), interval (every N seconds), timestamps (exact times). |
framesPerVideo | integer | 10 | Count mode: frames per video, 1-1000. |
intervalSeconds | string | 10 | Interval mode: seconds between frames. Decimals allowed. |
timestamps | array | [] | Timestamps mode: 95, 1:35, 0:01:35.5. Times past the end of a video are skipped, not charged. |
startTime / endTime | string | whole video | Count and interval modes: only take frames in this window. |
maxFramesPerVideo | integer | 100 | A cap for every mode, 1-1000. |
imageFormat | string | jpg | jpg, png (lossless) or webp (smallest). |
imageQuality | integer | 85 | 1-100, for JPG and WebP. |
maxWidth | integer | 0 | Scale frames down to at most this width (aspect ratio kept). 0 = the video's own size. |
contactSheet | boolean | false | Also make one JPG grid of each video's frames, free. |
proxyConfiguration | object | off | Not needed for most links. Apify Proxy or your own, for hosts that refuse cloud servers. |
{"videoUrls": ["https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/720/Big_Buck_Bunny_720_10s_1MB.mp4","https://example.com/media/product-demo.webm"],"mode": "interval","intervalSeconds": "2.5","imageFormat": "jpg","maxWidth": 1280,"contactSheet": true}
Output (one record per frame)
{"status": "ok","videoUrl": "https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/720/Big_Buck_Bunny_720_10s_1MB.mp4","videoIndex": 1,"frameNumber": 2,"timestampSeconds": 2.5,"timecode": "00:00:02.500","imageUrl": "https://api.apify.com/v2/key-value-stores/STORE_ID/records/001-Big_Buck_Bunny_720_10s_1MB-0002.jpg","imageKey": "001-Big_Buck_Bunny_720_10s_1MB-0002.jpg","imageFormat": "jpg","imageWidth": 1280,"imageHeight": 720,"imageBytes": 98213,"contactSheetUrl": "https://api.apify.com/v2/key-value-stores/STORE_ID/records/001-Big_Buck_Bunny_720_10s_1MB-sheet.jpg","durationSeconds": 10.0,"videoWidth": 1280,"videoHeight": 720,"fps": 30.0,"videoCodec": "h264","container": "mov","fileSizeBytes": 1053651,"bitrateKbps": 842,"extractedAt": "2026-10-21T09:00:00+00:00"}
- The images are stored in the run's key-value store;
imageUrlis a direct link to each one, and the "Images" tab of the run lists them all. Like all run storage on Apify, they are kept for the data retention period of your plan; copy them elsewhere if you need them longer. - For HLS links,
hlsVariantUrlis the variant playlist that was read. videoWidthandvideoHeightare the size the video is shown at (phone videos recorded in portrait are reported as portrait).- A video that cannot be read gives one record with
status: "failed"and anerrorin plain words (file not found, the server refused the download, not a video file, a link to a web page ...). A video where no asked-for time falls inside it givesstatus: "no-results". Neither is charged.
Pricing
Pay per event, no subscription.
| Event | Price | When it is charged |
|---|---|---|
| Frame | $0.001 | Once per frame image delivered. 10 frames from each of 20 videos = $0.20. |
Set a maximum charge in the run options and the actor stops before it would go over. Apify's standard run-start event adds $0.00005 per GB of run memory (the default 1 GB run: $0.00005).
Limits, stated plainly
- Direct links to video files only. Links to pages with a player (YouTube, TikTok, Instagram, Facebook, Vimeo, X, Dropbox and Google Drive share pages ...) are not video files; they are reported as failed and not charged. Downloading from those sites is against their terms.
- The video has to be reachable from Apify's cloud servers without a login. Some hosts refuse downloads from cloud servers (filesamples.com and media.w3.org did in our tests, with HTTP 403), and Wikimedia Commons limits how fast files can be downloaded; those videos are reported as failed and not charged. The optional proxy setting may help with some hosts.
- Live streams have no fixed length: use timestamps mode for them. DRM-protected streams cannot be read; fragmented-MP4 HLS with byte ranges or AES encryption goes to ffmpeg's own HLS reader, which may not seek.
- Speed depends on the video, because each frame is decoded from the keyframe before it. In the test at the default 1 GB, a video took 14 seconds (median, about 5 frames); frames from videos up to 640 px wide took about 2.5 seconds each and from 1080p about 7.5 seconds. 4K and long-keyframe videos are slower. More run memory also gives the run more CPU (1 GB = a quarter of a core), so 2-4 GB is faster for 1080p and 4K.
- PNG frames from 4K video are large (10 MB or more); JPG or WebP, or a
maxWidth, keep them small. - No scene-change detection yet: frames are chosen by time.
Privacy
Only the video links you give are fetched. Frames are stored only in your run's storage. The actor runs with limited permissions and reads nothing else in your account.