Extract frames from a video file, one per scene, with scene change detection: scene timestamps, JPEG keyframes (40 by default, 100 max) and an ffprobe summary as JSON. No ffmpeg to install, no extra API key. $0.01 a run plus $0.02 a video minute; failed videos are not charged.
The page now opens with what this Actor takes, what it returns and what it costs, with a working example input you can copy. It used to open by repeating its own title back to you.
The price is on the page, not only on the Pricing tab.
There is a ready-made example in the Examples tab, so you can run a real configuration without filling anything in.
0.5 - 2026-09-19
Long videos work now. Every video used to get the same 25 seconds of processing time,
whatever it was. That is not enough to scan a video longer than about three minutes at 1080p, so
longer videos timed out and came back as failures. The time a video gets is now set from its own
length and resolution, so a ten-minute 1080p video gets what it needs. You were never charged for
those failures. If you sent a long video and got a timeout, send it again.
The timeout message used to blame the wrong thing. It said the host you downloaded from was
slow and told you to try a different source URL. The download was never the problem and was never
counted against the budget. The message now says the video is long or high-resolution, which is
what actually ran out, and suggests a shorter or smaller version.
A very long, very high-resolution video can still run out of time, because the budget is
capped by what that video's own minutes are charged. It fails with a clear message and is not
charged.
A video that produced no stills is no longer charged. Scene detection used to be allowed to
spend the entire time budget, which could leave nothing for extracting the frames. The record
then came back marked complete, with the scene timestamps, no images, and a full charge. Frames
are what this Actor is for, so that case now fails and costs nothing. Detection is also capped
below the full budget so it cannot starve the frame step in the first place.
README corrections. It said "split any video", "one keyframe image per scene", "a full
ffprobe report" and "nothing to sign up for". Only the first two words of each were right: there
are size, length and resolution limits; stills are capped at 40 by default and 100 at most, so a
video with more scenes than that does not get a still for every scene; the report is ten fields,
not everything ffprobe returns; and you do need an Apify account. The 2160 px per side limit was
not written down anywhere and now is.
The price table in the README said $0.005 a minute. The price has been $0.02 a minute since
2026-09-18. The README was stale, not the bill. No price changed in this release.
Same inputs, same output fields, same prices.
0.4 - 2026-09-13
Links to private or internal addresses are now refused before anything is fetched, page links
included. A page link used to reach the page-to-video lookup before the address check ran, so a
link to an internal host could make that lookup open a connection to it. The check now runs
first. A link must be https, and a host that is, or looks up to, localhost, a private network, a
cloud metadata address or 100.64.x.x is refused.
100.64.x.x addresses are now refused on every link, direct media links included. It is a
shared address range used inside some networks, and it was not on the refused list before.
README: a new limit says what the check still cannot see. A host that gives a public address
when checked and a private one when the download connects (DNS rebinding), and a redirect or link
that the page-to-video lookup follows on its own.
Nothing else changes: the same inputs, the same output fields, the same prices.
0.3, platform build 0.3.4 - 2026-09-11 (run 18)
.actor/actor.json carries the colon title and the live description. Title: "Video Scene
Detection & Keyframe Extractor: no setup". It held a pre-2026-09-11 title and description. The
live title still carries an em dash until it is changed in Console, so the live title was not
copied.
README: two em dashes removed. The datasetId default reads "none", and the sceneThreshold
line uses a colon. checks/check_vocab.py now scans every Actor README for dashes.
0.1 - 2026-08-12
First build. One record per video: every scene boundary with start, end and duration; one
representative keyframe per scene in the key-value store; and an ffprobe report carrying
duration, resolution, frame rate, video and audio codec, audio presence, bitrate, file size and
container format.
No model and no API key. Every run produces the full product, so there is no preview mode and
nothing to sign up for before the first result.
Pay-per-event: $0.01 per run at start, $0.02 per minute of video, rounded up, minimum one minute
per video. Price scales with the work because processing cost does. Videos that fail to
download, resolve or decode are reported in the dataset and are not charged.
Accepts direct media URLs, a dataset id from any upstream scraper Actor, or page links resolved
best-effort. Dataset chaining is the documented primary path, because social platforms block
video fetching from datacenter IPs.
Each scene object carries the key-value store key of its own keyframe, so scenes and stills
never have to be joined by position.
Found during pre-ship QA and fixed before first publish:
A keyframe taken from the exact middle of a scene can land on a black transition frame. On the
Actor's own demo clip that happened to 1 scene in 5. Now, when the middle still looks empty,
the sampler tries a quarter and three quarters through the scene and keeps whichever has the
most in it. Costs about 0.1 s per affected video.
A video whose download consumed the whole per-video time budget used to return sceneCount: 1,
which is indistinguishable from a genuine single-shot video, and was charged for. It now fails
with a message saying the host was slow, and is not charged.
Found by the first real platform run, before publish:
An Actor with no pricing applied returned an empty dataset. Pricing on Apify is account
state, applied separately from the code, so every Actor passes through a "deployed but not yet
priced" window. In it, Actor.charge() does not raise: it logs a warning and reports zero
charged. That read as "the buyer's spend limit is exhausted" and stopped the run before it
delivered anything. An empty dataset is also how an Actor fails Apify's daily automated test.
A missing price now degrades to "process everything, bill nothing".
Per-minute price set from measurement on the platform rather than an estimate: $0.005 per
minute of video, 5x the measured marginal compute cost. See PLAN section 6 for the runs and
the arithmetic.