# Video Optimizer — Reduce FPS, Resize & Compress (CCTV, AI) (`adorable_partial/video-optimizer`) Actor

Shrink videos in bulk: lower FPS (30 to 5), downscale to 720p, compress to H.264 MP4 or fit under 16/25 MB. Presets for CCTV storage, AI inference, WhatsApp and e-mail. Removes GPS/device metadata. Pay per minute.

- **URL**: https://apify.com/adorable\_partial/video-optimizer.md
- **Developed by:** [Leandro Zanatta](https://apify.com/adorable_partial) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $21.00 / 1,000 video minute optimizeds

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

## Video Optimizer — Reduce FPS, Resize & Compress Videos

Shrink videos in bulk with one API call: **lower the frame rate** (for example 30 → 5 fps), **downscale to 720p**, **compress to H.264 MP4**, or **fit a target size** such as 16 MB. Ready-made presets for **CCTV / security camera storage**, **AI and computer vision inference**, **web**, **WhatsApp** and **e-mail**. Container metadata (device model, creation time, GPS location) is removed by default.

![Original 1080p video next to the CCTV preset output: same scene, 5.49 MB down to 0.31 MB](https://api.apify.com/v2/key-value-stores/ElfHz1cYtafK7Hdah/records/demo.png?signature=el0r27NH3USHrKZqxPCb)

*Real output of this Actor on a 13-second 1080p street clip (video: Qviri, CC BY-SA 4.0, Wikimedia Commons).*

### Why use it

- 💾 **Cut storage costs**: security footage rarely needs 30 fps and 1080p. The CCTV preset typically removes **90–95%** of the size while keeping people, vehicles and events clearly visible.
- 🤖 **Faster, cheaper AI pipelines**: object detectors, OCR and video analytics usually process 1–5 frames per second. Sending them a 5 fps, 640p file cuts upload, decoding and GPU time.
- 📤 **Files that actually send**: fit any clip under the 16 MB WhatsApp limit or the 25 MB e-mail attachment limit, automatically.
- 🔒 **Privacy by default**: removes metadata such as the recording device, creation date and GPS coordinates before you share or archive a file.
- 🧩 **No servers, no FFmpeg setup**: send URLs, get MP4 links back. Works from Python, JavaScript, Make, Zapier, n8n, webhooks and AI agents (MCP).

### Who uses it

| Sector | Typical use |
|---|---|
| **Security & CCTV integrators** | Archive weeks of camera exports in a fraction of the space; send clips to clients and insurers |
| **AI / computer vision teams** | Pre-process video before detection, tracking, OCR or labeling |
| **Logistics, fleets, dashcams** | Shrink driver and yard footage for upload over mobile networks |
| **Real estate, construction, drones** | Lighter inspection and site-progress videos for reports and portals |
| **Education & e-learning** | 720p versions of lectures for LMS platforms with upload limits |
| **Support & customer service** | Make customer-sent videos small enough for ticket systems and e-mail |
| **Marketing & social media** | Batch-convert raw footage (MOV, WebM, HEVC) into web-friendly MP4 |

### Presets

Measured on the 13-second, 1920×1080, 30 fps, 5.49 MB clip shown above:

| Preset | What it does | Result | Best for |
|---|---|---|---|
| **CCTV storage** (default) | 5 fps, max 720p, CRF 30, no audio | **0.31 MB (−94%)** | Archiving security-camera footage |
| **AI inference** | 5 fps, max 640p, CRF 23, no audio | **0.87 MB (−84%)** | Detection, tracking, OCR, video analytics |
| **Web 720p** | Max 720p, CRF 23, original fps and audio | **1.37 MB (−75%)** | Websites, LMS, internal portals |
| **Fit in 16 MB (WhatsApp)** | Max 720p, guaranteed under 16 MB | **1.37 MB (−75%)** | WhatsApp, Telegram, chat apps |
| **Fit in 25 MB (e-mail)** | Max 720p, guaranteed under 25 MB | **1.37 MB (−75%)** | E-mail attachments |
| **Custom** | Only what you set | — | Anything else |

**How the size presets work:** the video is first encoded at good quality with a bitrate cap. If it already fits, you get that file (a small video is never inflated to fill the limit). If it doesn't, the Actor runs a two-pass encode that lands just under the limit. If the video is simply too long for the limit, the run says so clearly instead of returning an unwatchable file; raise the size or set **Max minutes per video**.

Any field you fill in overrides the preset, so **CCTV storage + Target FPS 10** gives 10 fps with the rest of the preset.

### Input

| Field | Type | Description |
|---|---|---|
| **Video URLs** (`videoUrls`) | array | Direct links to videos. Public Google Drive and Dropbox share links are converted automatically. Up to 4 GB per file. |
| **Preset** (`preset`) | string | `cctv-storage`, `ai-inference`, `web-720p`, `whatsapp-16mb`, `email-25mb` or `custom` |
| **Target FPS** (`targetFps`) | integer | New frame rate. Never increases the original. |
| **Max height** (`maxHeight`) | integer | Downscale anything taller, keeping the aspect ratio. Never upscales. |
| **Quality (CRF)** (`crf`) | integer | 18 = near lossless, 23 = good, 28–32 = small files |
| **Target file size (MB)** (`targetSizeMB`) | integer | Keep each output under this size |
| **Remove audio** (`removeAudio`) | boolean | Drop the audio track |
| **Remove metadata** (`stripMetadata`) | boolean | Remove device, creation time and GPS (default: on) |
| **Max minutes per video** (`maxDurationMinutes`) | integer | Only the first N minutes are processed and billed (default 120) |

Example:

```json
{
  "videoUrls": [
    "https://example.com/camera-01.mp4",
    "https://drive.google.com/file/d/FILE_ID/view?usp=sharing"
  ],
  "preset": "cctv-storage",
  "targetFps": 3
}
```

**Supported inputs:** MP4, MOV, WebM, MKV, AVI, FLV, MPEG-TS and others; codecs H.264, H.265/HEVC, VP8, VP9, AV1, MPEG-4. **Output** is always H.264 MP4 with fast-start, which plays in every browser, phone and video player.

### Output

One dataset row per video. The optimized file is stored in the run's key-value store and linked in `outputUrl`.

```json
{
  "sourceUrl": "https://example.com/camera-01.mp4",
  "preset": "cctv-storage",
  "outputUrl": "https://api.apify.com/v2/key-value-stores/.../records/optimized-0001.mp4",
  "input":  { "durationSeconds": 13.07, "sizeMB": 5.49, "width": 1920, "height": 1080, "fps": 29.83, "videoCodec": "vp9", "audioCodec": "opus" },
  "output": { "durationSeconds": 13.0,  "sizeMB": 0.31, "width": 1280, "height": 720,  "fps": 5.0,   "videoCodec": "h264", "audioCodec": null },
  "sizeReductionPercent": 94.3,
  "truncated": false,
  "billedMinutes": 1
}
```

| Field | Meaning |
|---|---|
| `outputUrl` | Download link of the optimized MP4 |
| `input` / `output` | Duration, size, resolution, fps and codecs before and after |
| `sizeReductionPercent` | How much smaller the output is |
| `truncated` | `true` when only the first *Max minutes per video* were processed |
| `billedMinutes` | Started minutes billed for this video |
| `error` | Present only when a video failed (failed videos are free) |

Export the table as JSON, CSV or Excel, or read it through the API.

### Pricing

Pay per **started minute of video** processed, plus a tiny per-run start fee. No subscription. Failed videos are free. Apify plan discounts apply automatically (see the **Pricing** tab).

| Example | Minutes billed |
|---|---|
| 13-second clip | 1 |
| 10 clips of 30 seconds | 10 |
| 1 hour of CCTV footage | 60 |

Use **Max minutes per video** or the run's *maximum cost* setting to cap spending; the Actor stops cleanly when the limit is reached.

### Use it from code or an AI agent

**Python**

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("adorable_partial/video-optimizer").call(
    run_input={"videoUrls": ["https://example.com/camera-01.mp4"], "preset": "ai-inference"}
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["outputUrl"], item["sizeReductionPercent"])
```

**JavaScript**

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

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('adorable_partial/video-optimizer').call({
    videoUrls: ['https://example.com/clip.mov'],
    preset: 'whatsapp-16mb',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0].outputUrl);
```

**HTTP (one request, waits for the result)**

```bash
curl -X POST "https://api.apify.com/v2/acts/adorable_partial~video-optimizer/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"videoUrls": ["https://example.com/camera-01.mp4"], "preset": "cctv-storage"}'
```

**No-code and agents:** use the Apify modules in **Make**, **Zapier** or **n8n**, trigger runs from **webhooks** or **schedules** (e.g. every night on new camera exports), or let an AI agent call it through the **Apify MCP server**.

### FAQ

**Will the video look worse?** Lower fps and resolution are visible by design: the CCTV and AI presets trade smoothness for size, while people, vehicles and events stay clear. "Web 720p" keeps the original motion and good quality. For near-original quality use *Custom* with CRF 18–20.

**Can it make a video bigger or upscale it?** No. Resolution and fps are only ever reduced, and the size presets never inflate a file that already fits.

**How long can videos be?** Files up to 4 GB. Long recordings are processed in full unless you set *Max minutes per video* (default 120).

**How fast is it?** Roughly real-time or faster for 1080p input with the default 4 GB memory. More memory gives more CPU and faster runs.

**Does it remove GPS and device information?** Yes, container metadata is removed by default (`stripMetadata`). It does not blur faces or license plates; for that, see the related Actor below.

**Is my video kept?** Files are processed inside your run and stored only in your own Apify storage, which follows your account's data-retention settings. Nothing is shared with third parties.

**Private files?** Use direct download links (for example S3 / GCS pre-signed URLs) or public share links from Google Drive or Dropbox.

### Related Actors

- [Image & Video Anonymizer](https://apify.com/adorable_partial/image-anonymizer) — blur faces and license plates in photos and videos (GDPR / LGPD)
- [Video Frame Extractor for AI](https://apify.com/adorable_partial/video-frame-extractor-ai) — turn videos into clean image datasets
- [Audio Extractor](https://apify.com/adorable_partial/audio-extractor) — video to MP3, WAV or FLAC, speech-to-text ready
- [Audio & Video to Text (Whisper)](https://apify.com/adorable_partial/whisper-audio-video-transcriber) — transcripts and subtitles

### Support

Found a bug or need a preset for your workflow? Open an issue in the **Issues** tab and it will be answered there.

# Actor input Schema

## `videoUrls` (type: `array`):

Direct links to videos (MP4, MOV, WebM, MKV, AVI...). Public Google Drive and Dropbox share links work too.

## `preset` (type: `string`):

A ready-made combination of the settings below. Any field you fill in below overrides the preset.

## `targetFps` (type: `integer`):

Reduce the frame rate, e.g. 25 → 5. Leave empty to use the preset (or keep the original).

## `maxHeight` (type: `integer`):

Downscale videos taller than this, keeping the aspect ratio (720 = 720p). Smaller videos are never upscaled.

## `crf` (type: `integer`):

H.264 quality: 18 = near lossless, 23 = good, 28–32 = small files. Ignored when a target size is set.

## `targetSizeMB` (type: `integer`):

Encode in two passes to land just under this size. Overrides quality.

## `removeAudio` (type: `boolean`):

Drop the audio track (smaller files, no voices).

## `stripMetadata` (type: `boolean`):

Remove container metadata such as device model, creation time and GPS location.

## `maxDurationMinutes` (type: `integer`):

Only the first N minutes of each video are processed and billed.

## Actor input object example

```json
{
  "videoUrls": [
    "https://upload.wikimedia.org/wikipedia/commons/0/06/Roncesvalles_Ave_crossing_at_Galley_Ave%2C_PXO_Type_A_lights_flashing%2C_July_2026.webm"
  ],
  "preset": "cctv-storage",
  "stripMetadata": true,
  "maxDurationMinutes": 120
}
```

# Actor output Schema

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

One row per video: link to the optimized MP4, before/after size, resolution and FPS.

## `videos` (type: `string`):

The optimized MP4 files.

# 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 = {
    "videoUrls": [
        "https://upload.wikimedia.org/wikipedia/commons/0/06/Roncesvalles_Ave_crossing_at_Galley_Ave%2C_PXO_Type_A_lights_flashing%2C_July_2026.webm"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("adorable_partial/video-optimizer").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 = { "videoUrls": ["https://upload.wikimedia.org/wikipedia/commons/0/06/Roncesvalles_Ave_crossing_at_Galley_Ave%2C_PXO_Type_A_lights_flashing%2C_July_2026.webm"] }

# Run the Actor and wait for it to finish
run = client.actor("adorable_partial/video-optimizer").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 '{
  "videoUrls": [
    "https://upload.wikimedia.org/wikipedia/commons/0/06/Roncesvalles_Ave_crossing_at_Galley_Ave%2C_PXO_Type_A_lights_flashing%2C_July_2026.webm"
  ]
}' |
apify call adorable_partial/video-optimizer --silent --output-dataset

```

## MCP server setup

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

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/PVmsgb7efSYVsomd1/builds/KRHrfW1Vo5oyt9qtO/openapi.json
