MediaMetaX
Pricing
from $5.00 / 1,000 results
MediaMetaX
MediaMetaX is an Apify Actor designed to extract video and audio metadata quickly, accurately, and comprehensively using FFmpeg/FFprobe. It’s perfect for content creators, podcasters, video editors, media engineers, digital agencies, and developers who need technical media information.
Pricing
from $5.00 / 1,000 results
Rating
0.0
(0)
Developer
fanio zilla
Maintained by CommunityActor stats
0
Bookmarked
11
Total users
4
Monthly active users
a month ago
Last modified
Categories
Security
Limited permissionsShare
Video and audio metadata extraction with FFmpeg/FFprobe.
Download one video or audio file, read its technical metadata with FFprobe, optionally grab a thumbnail frame with FFmpeg, and publish one record to the dataset.
Built for content catalogs, podcast and video libraries, asset pipelines, and developers who need reliable media specs without running FFmpeg themselves.
What it does
Given a direct URL to a media file, the Actor downloads it to a temporary workspace, probes it, and publishes a single JSON record per run:
- Duration in seconds
- Bitrate in kbps
- Codec — the video codec, falling back to the audio codec
- Resolution and frame rate — video files only, omitted for audio-only
- Audio channel count — omitted when the file has no audio stream
- File size in bytes and container format
- Optional thumbnail — a JPEG frame grabbed at 1 second, stored in a key-value store, referenced by public URL
The file is streamed to disk and deleted when the run ends, successful or not.
Cost
Pay-per-event pricing. The platform charges two events:
| Event | Price | When it fires |
|---|---|---|
| Actor Start | $0.00005 | Once per run, based on allocated memory (1 event per GB, minimum 1) |
| Dataset Record | $0.005 | Once per successfully published record |
Two things worth knowing before you bill against this:
- A failed run still costs for Actor Start. The start charge is based on memory allocation, so a URL that 404s, times out, or is unreadable is billed for the start charge only. No extraction event is charged for failed runs.
- A dropped thumbnail is still billed as an extraction. If the thumbnail grab fails, the Actor
publishes the record without
thumbnailUrland charges the extraction event. The metadata record was delivered; the thumbnail is cosmetic. Check forthumbnailUrlrather than assuming success means you got one.
Standard platform fees for dataset and key-value store usage apply on top.
Input
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
mediaUrl | string | Yes | — | Direct HTTP/HTTPS URL to a video or audio file |
extractThumbnail | boolean | No | false | Grab a JPEG frame at the 1-second mark and attach its public URL to the record |
downloadTimeoutSecs | integer | No | 120 | Budget for one download attempt, shared by any redirects it follows |
mediaUrl must be a parseable http/https URL that answers with a non-empty body — directly, or
after up to 5 redirects. Direct file URLs work best — pages that link to media, or URLs requiring a
session or a referrer header, generally do not.
Input example
{"mediaUrl": "https://mdn.github.io/shared-assets/videos/flower.mp4","extractThumbnail": true}
Output
Every run publishes exactly one record to the dataset. Which of the two shapes you get is decided by
success.
Success record
{"success": true,"sourceUrl": "https://mdn.github.io/shared-assets/videos/flower.mp4","duration": 5.055,"bitrate": 1785,"codec": "h264","resolution": "960x540","fps": 29.97002997002997,"fileSize": 1128375,"format": "mov,mp4,m4a,3gp,3g2,mj2","audioChannels": 2,"thumbnailUrl": "https://api.apify.com/v2/key-value-stores/.../thumbnail.jpg"}
| Field | Type | Always present | Description |
|---|---|---|---|
success | boolean | Yes | true on this shape |
sourceUrl | string | Yes | The mediaUrl that was probed |
duration | number | Yes | Seconds. 0 when the container reports no duration |
bitrate | number | Yes | Kilobits per second, rounded down. 0 when unknown |
codec | string | Yes | Video codec, else audio codec, else "unknown" |
fileSize | number | Yes | Bytes. 0 when unknown |
format | string | Yes | Container format, e.g. mp4. "unknown" when absent |
resolution | string | No | WIDTHxHEIGHT, video streams only |
fps | number | No | Video streams only; omitted when the container reports a zero frame-rate denominator |
audioChannels | number | No | Omitted when the file carries no audio stream |
thumbnailUrl | string | No | Present only when extractThumbnail was requested and the frame was captured |
Fields marked "No" are genuinely absent from the record, not null — filter on key presence rather than truthiness if that distinction matters to your pipeline.
Failure record
{"success": false,"sourceUrl": "https://example.com/missing.mp4","error": "Failed to download file: HTTP 404"}
A failure record carries only success, sourceUrl, and error. It is published only once
mediaUrl is known — a run rejected during input validation has nothing to record against, so it
publishes nothing and exits non-zero.
Failure behavior
The Actor routes each kind of failure differently, and the route is decided in one place rather than at each throw site.
| What failed | Record published | Exit | Billed |
|---|---|---|---|
| Input validation | None | Non-zero | Actor Start only |
| Download | success: false | Non-zero | Actor Start only |
| Probe / unreadable media | success: false | Non-zero | Actor Start only |
| Thumbnail | success: true, without thumbnailUrl | Success | Actor Start + extraction |
| Unexpected internal error | success: false | Non-zero | Actor Start only |
A failed thumbnail is the only soft failure. The thumbnail is cosmetic, so the run degrades instead
of dying: the record still publishes, the run still exits successfully, and the run is still billed
as an extraction. Check for thumbnailUrl rather than assuming a successful run produced one.
A thumbnail that is captured but then fails to store is not softened — that is a platform failure, not a thumbnail failure, and the run fails.
Note: Actor Start is charged by the platform based on allocated memory and is separate from your code's extraction charge. This run never manually charges the start event.
Usage
Console
Fill in Media File URL, optionally tick Extract Thumbnail, and start the run. Results appear in the dataset tab; the thumbnail, if captured, appears under the run's key-value store.
API
curl -X POST \"https://api.apify.com/v2/acts/YOUR-USERNAME~video-audio-metadata-extractor/runs?token=YOUR_TOKEN" \-H "Content-Type: application/json" \-d '{"mediaUrl": "https://mdn.github.io/shared-assets/videos/flower.mp4","extractThumbnail": true}'
CLI
apify run \-c '{"mediaUrl":"https://mdn.github.io/shared-assets/videos/flower.mp4","extractThumbnail":true}' \-w
JavaScript SDK
import { Apify } from 'apify';const client = new Apify({ token: 'YOUR_TOKEN' });const run = await client.actor('YOUR-USERNAME/video-audio-metadata-extractor').call({mediaUrl: 'https://mdn.github.io/shared-assets/videos/flower.mp4',extractThumbnail: true,});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items[0]);
Supported formats
The Actor does not gate on file extension or container. Anything the bundled FFprobe build can read is accepted, which in practice means:
- Video — MP4, MOV, MKV, WebM, AVI, FLV, WMV, MPEG, 3GP
- Audio — MP3, AAC, WAV, FLAC, OGG, M4A, WMA
- Codecs — H.264, H.265/HEVC, VP8, VP9, AV1, AAC, MP3, FLAC, Opus, Vorbis
A file FFprobe cannot parse produces a probe-classified failure rather than a wrong answer.
Limits and notes
- One file per run. There is no batch input; schedule or loop the Actor over a list.
downloadTimeoutSecsper download attempt (120 by default), up to 3 attempts. Redirects are followed within an attempt, up to 5, and share that attempt's budget.httpandhttpsonly. Any other scheme fails immediately.- No file size limit. The download streams straight to disk, so memory use does not scale with file size. The practical ceiling is your run's disk and the timeout.
- Node.js 22, FFmpeg and FFprobe bundled in the image.
- Temporary files are always cleaned up, including on failure.
Development
apify run # run locallynpm test # hermetic suite, no network or FFmpeg needednpm run build # compile to dist/
Platform-level test specification
The hermetic suite cannot verify charging against the platform's registered pay-per-event events —
that requires the real platform pricing table. A Jasmine-style spec at .actor/spec.js drives the
deployed Actor on the Apify platform to verify:
- Exact charge sequences on success and failure paths
- Deployed build matches the repository
- Completion within the Store's five-minute test budget
- Non-empty dataset on successful runs
Run on demand after deployment:
$apify call actorify/actor-testing -f .actor/spec-input.json --json
This is not part of the PR workflow (it costs money and needs a deployed build). Run it on demand or set up a scheduled workflow if automated verification is desired.
Architecture
- ./docs/adr/0001-failure-routing-lives-in-one-route-table.md
- ./docs/adr/0002-charging-at-the-success-seam.md
- ./docs/adr/0003-ports-and-fakes-testing.md
- ./docs/adr/0004-no-downloader-seam.md