Extract frames from a video
Turn a video into a sequence of still images without opening an editor: pick how many frames per second to sample, and get back each frame as a separate image. It exists for anyone who needs thumbnails, dataset samples, or visual proof at scale, not one video at a time by hand.
This task is not available right now, so it cannot be purchased. Nothing is charged for it.
How it works & APIWhy pull frames programmatically
Teams that generate thumbnails for a video catalog, build training data for a computer-vision model, or need a quick visual index of hours of footage all hit the same wall: doing it by hand in a desktop tool doesn't scale past a handful of files. The extract frames from video api endpoint replaces that manual scrubbing with a single call that returns exactly the images you asked for, in the order you asked for them.
How a request behaves
Call POST /video/frames with a link to your source video and your sampling rate in frames per second — how many frames to pull from each second of video, spread evenly across the clip. The task is queued, processed asynchronously, and you get a task_id immediately; the frames themselves arrive later as a signed link or, if you prefer not to poll, a signed webhook call the moment the job finishes. Whatever sampling you ask for, a single request returns at most 300 frames — at one frame per second that's roughly the first five minutes of video, and a denser rate reaches the cap sooner.
What comes back
Each extracted frame is delivered as a standard image file, named and ordered so you can map it straight back to its timestamp in the source video. There is no resizing forced on you and no watermark added; you get the pixels as they existed in that frame, ready to feed into a thumbnail grid, a labeling pipeline, or a moderation queue.
A quick note on how video sampling works
Video is just a sequence of encoded frames shown fast enough to look continuous; extracting a still frame means decoding to the nearest frame at each sampling point, and a steady rate — say, one frame every two seconds — stays fast and predictable even across a long file.
Where it fits in a pipeline
Because the call is async and billed only on success, it slots cleanly into a larger automation: a script that uploads new videos, calls this endpoint, waits for the webhook, and hands the frames to whatever downstream step needs them, whether that's a thumbnail selector, an object detector, or a manual review dashboard.
What you can do with it
Auto-generated thumbnails
A video platform requests one frame every 10 seconds for each new upload, then lets an internal tool pick the sharpest one as the cover image.
Training data for computer vision
A team building a defect-detection model extracts a frame every 0.5 seconds from factory-floor footage to build a labeled image dataset.
Evidence capture
A compliance workflow samples frames across the window flagged by a separate audio transcript to document what was on screen when something was said.
Storyboard previews
A marketing team samples a frame every few seconds from a rough cut to build a quick visual storyboard for client review, no editing software required.
FAQ
How do I extract frames from a video using the API?
Send a POST request to /video/frames with your video source and a sampling rate in frames per second; you get a task_id back immediately and the frames later via webhook or signed link.
Is there a free tier to test frame extraction?
There's no free tier — free tiers get abused and slow everyone down. Access runs on a prepaid ForHosting KIT balance: top up from $10.00 (it never expires) and each request is charged at its published price, so a call with no balance returns HTTP 402. No subscription, no tokens, no invented credits, and a failed task is never charged.
What image formats do I get back?
Frames are delivered as standard PNG or JPG files at the source video's native resolution, unless you request otherwise.
Can I target exact timestamps, or only a steady rate?
Extraction is by frame rate — you set how many frames per second to sample and they're spread evenly across the video; targeting individual arbitrary timestamps isn't supported. If you need fine granularity, sample densely over a short clip.
How is the extraction priced?
It's $0.077 per request plus $0.0045 per minute of video processed, published up front with no token system.
What happens if my job fails?
Failed tasks are retried automatically up to three times; if it still fails you get a clear error and you are never charged for a failed job.
How long do I have to download the results?
The signed link is valid for 24 hours, and the source and output files are deleted after the retention period; nothing is kept for training.
Is there a limit on how many frames I get back?
Yes — extraction is capped at 300 frames per request. At one frame per second that covers about the first five minutes of the clip; a higher rate reaches the 300-frame limit sooner, so pick a rate that lands the frames you actually need.
Is this endpoint live right now?
It's in final deployment and not yet accepting jobs; it will be available very soon under the same endpoint and pricing described here.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
One authenticated POST creates the task; the result comes back by webhook or a signed link. This capability is currently available through the API, not as an interactive Web tool.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/video/frames \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"video":"https://example.com/clip.mp4"}'const res = await fetch("https://api.kit.forhosting.com/video/frames", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"video": "https://example.com/clip.mp4"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/video/frames",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"video": "https://example.com/clip.mp4"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/video/frames", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"video":"https://example.com/clip.mp4"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"video":"https://example.com/clip.mp4"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/video/frames", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"video": "https://example.com/clip.mp4"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "video.frames",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
max_mb | 500 |
max_minutes | 60 |
max_megapixels | 3.9 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |