# Audio and Video Convert — extract audio, transcode, trim, GIF (`hermeskd/audio-video-convert`) Actor

One media file URL and an operation in, one file out: extract the audio track (MP3, WAV, M4A, OGG), convert audio, transcode video to MP4 or WebM, trim, compress to a size, or make a GIF. Pay per minute.

- **URL**: https://apify.com/hermeskd/audio-video-convert.md
- **Developed by:** [Logan Parker](https://apify.com/hermeskd) (community)
- **Categories:** Agents, Videos, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $12.00 / 1,000 video minute processeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

Give it one media file URL and an operation: extract the audio track (MP3, WAV, M4A, OGG; e.g. 16 kHz mono for speech recognition), convert audio, transcode video (MP4 H.264 or WebM), trim to a time range, compress to a target size, or make a GIF from a segment. The result is a file in the run's key-value store. Agents chaining media steps — shrink a video before an upload, cut a clip, pull the audio out for a transcription model — get the ffmpeg step without a machine of their own: one call returns one record with the file's URL, format, duration and size, and pricing is per started minute of input, so pulling the audio out of a short video costs a tenth of a cent.

### Call it from an agent

Through Apify's MCP server (`https://mcp.apify.com`), tool `call-actor`:

```json
{"actor": "hermeskd/audio-video-convert", "input": {"url": "https://media.w3.org/2010/05/sintel/trailer.mp4", "operation": "extract_audio", "audioFormat": "mp3"}, "callOptions": {"maxTotalChargeUsd": 0.05, "timeout": 3600}, "waitSecs": 30}
```

The call returns the run's status and its `defaultDatasetId`. Read the record with `get-dataset-items`:

```json
{"datasetId": "<defaultDatasetId from the call>", "limit": 50}
```

The record's `outputUrl` is the converted file in the run's key-value store; fetch it from there. As a dedicated tool, add `https://mcp.apify.com?tools=hermeskd/audio-video-convert` to your MCP client. Extracting the audio of a short clip finishes well inside the 30-second wait; a long video transcode takes minutes, so poll the run, or call with a larger `waitSecs`. `maxTotalChargeUsd` caps what the run can charge: a file whose minutes would cost more than the cap is not processed and comes back as `charge_limit_reached`, uncharged.

### Input

| Field | Type | Required | Default | Meaning |
|---|---|---|---|---|
| `url` | string | yes | — | One audio or video file URL, http or https, up to 1 GB (MP4, MOV, MKV, WebM, AVI, FLV, MPEG-TS, MP3, WAV, M4A, AAC, OGG, FLAC and other single-file formats; not a playlist). |
| `operation` | enum `extract_audio` · `convert_audio` · `transcode_video` · `trim` · `compress_video` · `gif` | yes | — | What to do (below). |
| `audioFormat` | enum `mp3` · `wav` · `m4a` · `ogg` | no | `mp3` | For audio outputs: MP3 (VBR about 165 kbps), WAV (16-bit PCM), M4A (AAC 160 kbps) or OGG (Vorbis). |
| `sampleRate` | integer | no | source | Resample audio outputs, e.g. 16000 for speech models: 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100 or 48000 Hz. |
| `channels` | integer | no | source | 1 (mono) or 2 (stereo); a source with more than two channels is mixed down to stereo. |
| `videoFormat` | enum `mp4` · `webm` | no | `mp4` | For video outputs: MP4 (H.264 + AAC) or WebM (VP9 + Opus). |
| `start` | integer | no | 0 | For `trim` and `gif` only: start of the range, whole seconds (0–86,400). |
| `end` | integer | no | end | For `trim` and `gif` only: end of the range, whole seconds (1–86,400), after `start` and inside the media; a value inside the media's last partial second means the end. |
| `targetSizeMb` | integer | no | — | For `compress_video`, where it is required: the largest output size, in megabytes of 1,000,000 bytes (1–1,000). |
| `maxWidth` | integer | no | source | Scale video and GIF outputs down to this width, keeping the aspect ratio (16–7,680 px). Video outputs are capped at 1080p (1920×1080, either orientation) and GIFs at 640 px a side whatever this says. A GIF defaults to 480 px when the source is wider. |

What each operation does:

- `extract_audio` — the first audio track of a video (or audio) file, as `audioFormat`. A file with no audio track is `no_audio_stream`.
- `convert_audio` — an audio file to `audioFormat`, with `sampleRate` and `channels` if given.
- `transcode_video` — the whole video to `videoFormat` at the source's size (or `maxWidth`) and frame rate, quality-targeted. A source larger than 1080p is scaled to fit 1920×1080 (1080×1920 for a portrait video) and the record's `warnings` says `scaled_to_1080p`.
- `trim` — the `start`–`end` range, re-encoded so the cut is frame-accurate: a video to `videoFormat`, an audio-only file to `audioFormat`.
- `compress_video` — the whole video to `videoFormat` at the bitrate that lands it under `targetSizeMb`; if the first pass comes out over, a second pass at a lower bitrate. Setting `maxWidth` too keeps a small target watchable.
- `gif` — the `start`–`end` range (at most 60 seconds) as a looping GIF at up to 10 frames a second and at most 640 px a side (`warnings`: `scaled_to_640px` when that cap applied), with a palette built from the clip.

`start` and `end` are refused on the other operations (processing the whole file instead would charge more than asked). Metadata — tags, chapters, location — is not copied to the output. Every limit above is enforced by the input schema and again in code.

### Output

One record per run (the Actor takes one file).

| Field | Meaning |
|---|---|
| `url` | The input URL. |
| `ok` | `true` when the output file was written; `false` with `error`. |
| `operation` | The operation run. |
| `key` | The output file's key in the run's default key-value store: `output.<format>`. |
| `outputUrl` | API URL of that key-value store record — the converted file. |
| `format` | The output's format: `mp3`, `wav`, `m4a`, `ogg`, `mp4`, `webm` or `gif`. |
| `durationSec` | The output's duration in seconds, as ffprobe reads it. |
| `sizeBytes` | The output's size in bytes. |
| `width` | The video or GIF output's width in pixels; `null` for audio outputs. |
| `height` | The video or GIF output's height in pixels; `null` for audio outputs. |
| `minutesCharged` | Started minutes of input processed, charged as `event`: the whole file's duration, or for `trim` and `gif` the selected range (`end` − `start`). |
| `event` | The event `minutesCharged` counts: `audio-minute-processed` when the output is audio only; for video and GIF outputs `hd-video-minute` when the output or the source video has more pixels than 1280×720 (720p), `video-minute-processed` otherwise. |
| `warnings` | `scaled_to_1080p` when a video output was scaled down to fit 1920×1080; `scaled_to_640px` when a GIF was scaled down to 640 px a side. Empty otherwise. |
| `error` | `{code, message}` when `ok` is `false`. |

Example record for the `trim` example task (a 15-second clip of Big Buck Bunny), as this Actor's conversion returned it on 2026-10-16; the store id in `outputUrl` is the run's own:

```json
{
  "url": "https://raw.githubusercontent.com/mediaelement/mediaelement-files/4d21a042353022326071acb0251ab75cd6bae114/big_buck_bunny.mp4",
  "ok": true,
  "operation": "trim",
  "key": "output.mp4",
  "outputUrl": "https://api.apify.com/v2/key-value-stores/STORE_ID/records/output.mp4",
  "format": "mp4",
  "durationSec": 15.0,
  "sizeBytes": 1063409,
  "width": 640,
  "height": 360,
  "minutesCharged": 1,
  "event": "video-minute-processed",
  "warnings": []
}
```

### Events and prices

Pay per event; platform usage is included in the price, never passed through.

| Event | Title | Charged when | FREE / BRONZE | SILVER | GOLD / PLATINUM / DIAMOND |
|---|---|---|---|---|---|
| `audio-minute-processed` | Audio minute processed | One started minute of input processed by an operation whose output is audio only. | $0.001 | $0.0009 | $0.0008 |
| `video-minute-processed` | Video minute processed | One started minute of input processed by an operation whose output is video or GIF. | $0.015 | $0.0135 | $0.012 |
| `hd-video-minute` | HD video minute processed | One started minute of input processed by an operation whose output is video or GIF, when the output or the source video has more pixels than 1280x720 (720p); charged instead of video-minute-processed. | $0.045 | $0.0405 | $0.036 |

A started minute counts whole: 52 seconds is one minute, 60.1 seconds is two. Apify also charges its standard `apify-actor-start` event: $0.00005 per GB of run memory (one event, $0.00005, at the default 1,024 MB). The minimum maximum-charge a caller can set is $0.05.

Worked examples on the FREE tier: the call above (the 52-second Sintel trailer to MP3) is one audio minute, $0.001, plus $0.00005 for the start: $0.00105. Transcoding a 9 min 56 s video to WebM is ten video minutes, $0.15, plus the start: $0.15005. A 4-second GIF cut from a 10-minute video is one video minute, $0.015 — the range is charged, not the file. Transcoding the same 9 min 56 s film from its 1080p source to WebM is ten HD video minutes, $0.45, plus the start — HD is charged when either the source or the output is above 720p, because decoding a 1080p or 2160p source costs as much as encoding the output: scaling a 1080p source down to 480p is still an HD minute. Nothing is charged for a failed run.

### Limits and run time

- One file per run, up to 1 GB. Files download at 2 MB/s or faster: each download has a budget of 30 s plus 1 s per 2 MB of the file (a 100 MB file: 80 s), and one that sends nothing for 30 s is stopped; a slower source is `download_failed`. At most 2 requests a second go to one host.
- `start` and `end` are whole seconds; a GIF covers at most 60 seconds; `targetSizeMb` 1–1,000.
- The default memory is 1,024 MB, a quarter of a CPU core on Apify; ffmpeg runs one thread per core the run has. Measured on one core of the build machine (Apify's cores may be slower): extracting audio takes about 1 core-second per minute of input; a video minute takes about 22 core-seconds to MP4 at 720p and 24 at 1080p (1080p and larger use x264's fastest preset), 18 and 39 to WebM; a 60-second GIF about 11. At the default memory a 720p video minute therefore takes about 1.5 minutes of run time — give long videos 4,096 MB (one core) or more to finish four times sooner; the price per minute is the same.
- Video outputs are at most 1080p (a larger source is scaled to fit 1920×1080, either orientation, and the record says `scaled_to_1080p`); GIFs at most 640 px a side. Source videos up to 3840×2160 (4K UHD) are taken for every video operation; a larger one is `unsupported_media` (`extract_audio` works on any). Measured on one core of the build machine, a minute from a 1080p source to 1080p WebM takes about 41 core-seconds and to MP4 27; from a 2160p source about 76 and 63; a 60-second GIF from a 2160p source about 58. HD and long videos run several times longer than the default memory's quarter core allows in a few minutes: give them 4,096 MB (one core) or more. The default run timeout is 3,600 seconds; a conversion still running when it ends is `timeout`.
- GitHub release links (`github.com/…/releases/download/…`) are refused with `robots_disallowed`: github.com's robots.txt disallows every crawler, HermesBot included. Use the file's `raw.githubusercontent.com` address, or your own storage.
- Typical run time: the call above in a few seconds plus the start; a 10-minute 180p video to WebM in about two minutes at the default memory.

### Errors

Errors are records with `ok: false` and `error.code`; none is charged.

| `error.code` | Meaning |
|---|---|
| `download_failed` | The URL did not return the file: an HTTP error status, a network error, or slower than 2 MB/s (its download budget ran out, or 30 s without data). |
| `unsupported_media` | Not a decodable single-file audio or video format (a playlist, a text file, a damaged or truncated file), no stream the operation needs (a video operation on an audio-only file), or a video operation on a source larger than 3840×2160. |
| `no_audio_stream` | `extract_audio` or `convert_audio` on a file with no audio track. |
| `too_large` | Over 1 GB. |
| `invalid_range` | `start` or `end` outside the media, `end` not after `start`, or a GIF range over 60 seconds. |
| `robots_disallowed` | robots.txt forbids fetching the URL; no request was made to it. |
| `blocked_host` | The host is on the deny-list, or resolves to a private or local address. |
| `timeout` | The download or the conversion did not finish within the run's time budget. |
| `internal_error` | Unexpected failure; the message carries the class. |
| `charge_limit_reached` | The file's minutes would cost more than the run's maximum total charge; it was not converted. |
| `invalid_input` | The run input passed the input schema but cannot be used (for example `compress_video` without `targetSizeMb`, `start` on `extract_audio`, or a `targetSizeMb` too small for the video's length); the message names the field. Nothing is converted. |

The run fails only when its input failed with an Actor-side code (`internal_error`, `timeout`), so a broken Actor is visible. Every other run succeeds — including one where nothing was converted because of the caller's own input (bad URL, robots, deny-list, an undecodable file, a bad range, invalid input, the charge limit).

### Sources and terms

The source is the caller's media file. Process only media you have the right to process. Fetching follows the Hermes fetch policy: robots.txt is obeyed for the user-agent `HermesBot` (and `*`), and a disallowed URL is refused without a request; platforms whose terms forbid automated access (video platforms and social networks among them), and people-search sites, are on a deny-list and refused without a request; private and local addresses are refused, after DNS and on every redirect; the user-agent is `HermesBot/1.0 (+https://apify.com/hermeskd)`; no login, cookies, credentials, CAPTCHA solving, evasion or proxies are used. The file is opened by ffmpeg as one local file in an allow-listed container format: playlists and manifests, which would make ffmpeg fetch further URLs or read other files, are refused. The converted file is returned to the caller; no speaker or face is identified, and metadata is dropped.

### Not affiliated

This Actor is not affiliated with the FFmpeg project, the W3C, the Blender Foundation or LibriVox. FFmpeg (with x264, libvpx, Opus, LAME and Vorbis) is used under its open-source licences; the example media are Blender Foundation films under CC BY 3.0 and a public-domain LibriVox recording.

### Related Hermes Actors

- `pdf-to-markdown` — PDF documents to Markdown, with OCR for scanned pages.
- `document-to-markdown` — Word, PowerPoint, Excel and other office files to Markdown.
- `image-to-text` — the text in images, by OCR.
- `audio-to-transcript` — speech to text (feed it this Actor's 16 kHz mono WAV).
- `video-frames` — frames and metadata from a video.
- `image-upscale` — image upscaling.
- `url-to-markdown` — a web page to Markdown.

### Changelog

- 1.0 (2026-10-17) — first release: extract and convert audio (MP3, WAV, M4A, OGG), transcode video (MP4, WebM), trim, compress to a size, GIF; per-minute pricing, HD minutes (source or output above 720p) as `hd-video-minute`; video outputs at most 1080p, GIFs at most 640 px a side.

# Actor input Schema

## `url` (type: `string`):

One audio or video file URL, http or https, up to 1 GB (MP4, MOV, MKV, WebM, AVI, FLV, MPEG-TS, MP3, WAV, M4A, AAC, OGG, FLAC and other single-file formats; not a playlist).

## `operation` (type: `string`):

extract_audio: the audio track as audioFormat. convert_audio: an audio file to audioFormat. transcode_video: to videoFormat (MP4 = H.264 + AAC, WebM = VP9 + Opus). trim: the start–end range, re-encoded frame-accurately. compress_video: to targetSizeMb. gif: an animated GIF of the start–end range.

## `audioFormat` (type: `string`):

For audio outputs (extract_audio, convert_audio, trim of an audio file): mp3 (VBR about 165 kbps), wav (16-bit PCM), m4a (AAC 160 kbps) or ogg (Vorbis).

## `sampleRate` (type: `integer`):

Resample audio outputs to this rate, e.g. 16000 for speech models: 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100 or 48000. Empty keeps the source rate.

## `channels` (type: `integer`):

Audio channels of the output: 1 (mono, e.g. for speech models) or 2 (stereo). Empty keeps the source's, with more than two mixed down to stereo.

## `videoFormat` (type: `string`):

For video outputs (transcode_video, compress_video, trim of a video): mp4 (H.264 + AAC) or webm (VP9 + Opus).

## `start` (type: `integer`):

For trim and gif only: where the range starts, in whole seconds from the beginning (0–86,400). Default 0.

## `end` (type: `integer`):

For trim and gif only: where the range ends, in whole seconds (1–86,400); after start, inside the media. Empty means the end of the media. A GIF covers at most 60 seconds.

## `targetSizeMb` (type: `integer`):

For compress_video (required there): the largest output size in megabytes of 1,000,000 bytes (1–1,000). The bitrate is set from it and the file's duration.

## `maxWidth` (type: `integer`):

Scale video and GIF outputs down to this width, keeping the aspect ratio (16–7,680). Empty keeps the source width; a GIF defaults to 480 px when the source is wider.

## Actor input object example

```json
{
  "url": "https://media.w3.org/2010/05/sintel/trailer.mp4",
  "operation": "extract_audio",
  "audioFormat": "mp3",
  "videoFormat": "mp4"
}
```

# Actor output Schema

## `results` (type: `string`):

One record with ok, operation, format, durationSec, sizeBytes, minutesCharged, the file key and its URL, or an error code.

## `files` (type: `string`):

The output audio, video or GIF file (output.mp3, output.mp4, output.gif, …) in the run's key-value store.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "url": "https://media.w3.org/2010/05/sintel/trailer.mp4",
    "operation": "extract_audio",
    "audioFormat": "mp3"
};

// Run the Actor and wait for it to finish
const run = await client.actor("hermeskd/audio-video-convert").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "url": "https://media.w3.org/2010/05/sintel/trailer.mp4",
    "operation": "extract_audio",
    "audioFormat": "mp3",
}

# Run the Actor and wait for it to finish
run = client.actor("hermeskd/audio-video-convert").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "url": "https://media.w3.org/2010/05/sintel/trailer.mp4",
  "operation": "extract_audio",
  "audioFormat": "mp3"
}' |
apify call hermeskd/audio-video-convert --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,hermeskd/audio-video-convert"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/xSQncUIiFESOnb5fw/builds/LtEvyGhSc99d2DhfJ/openapi.json
