# Video Frame Extractor: YouTube, TikTok & MP4 to Images (`parsebird/video-frame-extractor`) Actor

Extract frames from YouTube, TikTok, Instagram, Facebook, X and MP4 videos as JPG, PNG or WebP images: evenly spaced, every N seconds, at scene changes, keyframes or exact timestamps, plus contact sheets.

- **URL**: https://apify.com/parsebird/video-frame-extractor.md
- **Developed by:** [ParseBird](https://apify.com/parsebird) (community)
- **Stats:** 6 total users, 1 monthly users, 85.7% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.39 / 1,000 frames

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 Frame Extractor

Video Frame Extractor **turns YouTube, TikTok, Instagram, Facebook, X and MP4 videos into still images**. Pick frames evenly spaced, every N seconds, at each scene change, at the video's keyframes or at exact timestamps, and get them as JPG, PNG or WebP files with a link and timestamp for every frame.

<table><tr>
<td style="border-left:4px solid #E5484D;padding:12px 16px;font-weight:600">
Paste up to 100 video links, choose how frames are picked, and download the images from Apify storage, with an optional contact sheet per video. No video download, no software to install: only the parts of the video needed for each frame are fetched.
</td>
</tr></table>

##### Copy to your AI assistant

Copy this block into ChatGPT, Claude, Cursor, or any LLM to start using this actor.

```
Use the Apify Actor "parsebird/video-frame-extractor" (call it via ApifyClient) to extract still frames from videos as images. Example (JavaScript): const { ApifyClient } = require('apify-client'); const client = new ApifyClient({ token: '<APIFY_TOKEN>' }); const run = await client.actor('parsebird/video-frame-extractor').call({ videoUrls: ['https://www.youtube.com/watch?v=aqz-KE-bpKQ'], mode: 'scenes', maxFramesPerVideo: 30, contactSheet: true }); const { items } = await client.dataset(run.defaultDatasetId).listItems(); Inputs: videoUrls (required array of links: YouTube videos and Shorts, TikTok, Instagram reels/posts, Facebook videos/reels, X posts, other yt-dlp sites, direct MP4/WebM/MOV/M3U8 files; max 100), mode (string, default "count"; count/interval/scenes/keyframes/timestamps), frameCount (integer 1-1000, default 10, count mode), intervalSeconds (number >= 0.1, default 5, interval mode), sceneThreshold (number 0.01-0.99, default 0.3, scenes mode), timestamps (array of times like "90", "1:30", "00:01:30.250", "1m30s"; timestamps mode), startTime and endTime (strings like "30", "0:30", "1m"; not used in timestamps mode), outputFormat (jpg/png/webp, default jpg), maxWidth (integer px, default 1280, 0 = original), maxFramesPerVideo (integer 1-1000, default 100), contactSheet (boolean, default false), contactSheetColumns (integer 1-12, default 5), proxyMode (auto/none/datacenter/residential, default auto), maxDownloadMbPerVideo (integer MB, default 500, 0 = no limit). The dataset has two row types: recordType "frame" (videoUrl, videoTitle, videoId, platform, mode, frameIndex, timestampSec, timestamp, sceneScore, width, height, imageFormat, kvKey, frameUrl, durationSec, proxyUsed) and recordType "video" (status ok/failed/skipped, videoUrl, videoTitle, videoId, platform, mode, durationSec, framesExtracted, contactSheetUrl, transferredMb, minutesScanned, proxyUsed, error). Images are in the run's default key-value store under kvKey; frameUrl links to them. API docs: https://apify.com/parsebird/video-frame-extractor/api. Get a token at https://console.apify.com/settings/integrations.
```

### What is Video Frame Extractor?

**Video Frame Extractor** is an [Apify Actor](https://apify.com/actors) that extracts frames from online videos and saves them as images. It works with **YouTube** (videos and Shorts), **TikTok**, **Instagram** reels and posts, **Facebook** videos and reels, **X (Twitter)** posts, many other sites supported by [yt-dlp](https://github.com/yt-dlp/yt-dlp), and **direct video files** such as MP4, WebM, MOV and M3U8 (HLS) streams.

You don't need ffmpeg, a video editor or an API key. Paste links, pick a mode, click **Start**, and each frame lands in Apify storage with its timestamp and a download link. It's a quick way to make thumbnails, storyboards and image datasets from video, or to grab a screenshot from a YouTube video at an exact time.

### What can Video Frame Extractor do?

- 🎞️ **Five extraction modes**: a fixed number of frames, one frame every N seconds, one frame per shot change, the video's keyframes, or a list of exact timestamps.
- 🌐 **Many sources**: YouTube, YouTube Shorts, TikTok, Instagram, Facebook, X, other yt-dlp sites and direct video links, mixed in one run (up to 100 links).
- ⚡ **Fetches only what it needs**: for single frames it seeks inside the video instead of downloading it, and it uses the smallest stream that reaches your chosen width. HLS streams are cut to the one segment holding each frame.
- 🖼️ **JPG, PNG or WebP**, scaled down to a maximum width (or kept at the original resolution).
- 🗂️ **Contact sheets**: one grid image per video with up to 100 frames, each stamped with its timestamp.
- ⏱️ **Start and end times**: limit any mode to part of the video, for example 1:00 to 5:00.
- 🛡️ **Proxy only when needed**: Auto mode tries a direct connection first, then datacenter proxies, and uses a residential proxy only when a site blocks the others.
- 🔌 **Platform features**: [schedule](https://docs.apify.com/platform/schedules) runs, call the Actor from the [Apify API](https://docs.apify.com/api/v2), get [webhooks](https://docs.apify.com/platform/integrations/webhooks) when a run finishes, and connect it to [Make, Zapier, n8n, Google Drive and more](https://apify.com/integrations). Export the frame list as JSON, CSV, Excel or HTML.

#### Extraction modes

| Mode | What it does | Good for |
|------|--------------|----------|
| Count | N frames spread evenly; each one comes from the middle of an equal slice of the video, which avoids black lead-in and fade-out frames | Thumbnails, previews, quick visual summaries |
| Interval | One frame every N seconds (every 5 s, or every 0.5 s) | Image datasets, monitoring footage, step-by-step tutorials |
| Scenes | The opening frame plus one frame at each shot change, with a sensitivity threshold and a score per frame | Storyboards, ad and trailer breakdowns, video indexing |
| Keyframes | The video's own keyframes (I-frames) | Fast sampling that follows the encoder's own cuts |
| Timestamps | The exact times you list (90, 1:30, 00:02:15.5, 1m30s) | Grabbing moments you already know |

Every mode respects **Max frames per video**. In scenes mode the strongest scene changes are kept, in keyframes mode the keyframes are sampled evenly, and in interval mode the first frames are kept.

### What data do you get?

Each frame is saved as an image in the run's key-value store, and the dataset gets one row per frame plus one summary row per video.

| Field | Description |
|-------|-------------|
| `recordType` | `frame` for a frame, `video` for a video summary |
| `frameUrl`, `kvKey` | Link to the image and its key in the key-value store |
| `timestampSec`, `timestamp` | Where the frame is in the video, in seconds and as `00:01:08.200` |
| `frameIndex` | Position of the frame within its video |
| `sceneScore` | How strong the shot change was (scenes mode, 0–1) |
| `width`, `height`, `imageFormat` | Size and format of the saved image |
| `videoTitle`, `videoId`, `platform`, `durationSec` | The source video |
| `status`, `error` | Video row: `ok`, `failed` or `skipped`, and why |
| `framesExtracted`, `contactSheetUrl` | Video row: frame count and the contact sheet link |
| `transferredMb`, `minutesScanned`, `proxyUsed` | Video row: data fetched, minutes scanned in scenes mode, and the network route used |

Filter on `recordType` to keep only frames when you export to CSV, Excel or Google Sheets.

### How to extract frames from a video

1. Open [Video Frame Extractor](https://apify.com/parsebird/video-frame-extractor) in Apify Console and create a free Apify account if you don't have one.
2. Paste one or more video links into **Video URLs**.
3. Choose an **Extraction mode** and its setting, for example 10 frames, a 5-second interval or a scene sensitivity of 0.3.
4. Optionally set a start and end time, the image format, the max width and a contact sheet.
5. Click **Start**. When the run finishes, open the **Output** tab to see every frame, or open the key-value store to download the images.

### Input examples

#### 10 evenly spaced frames from a direct MP4

```json
{
    "videoUrls": ["https://media.w3.org/2010/05/sintel/trailer.mp4"],
    "mode": "count",
    "frameCount": 10
}
```

#### A storyboard of a YouTube video, with a contact sheet

```json
{
    "videoUrls": ["https://www.youtube.com/watch?v=aqz-KE-bpKQ"],
    "mode": "scenes",
    "sceneThreshold": 0.3,
    "maxFramesPerVideo": 30,
    "contactSheet": true
}
```

#### Two frames per second from part of a video, as WebP

```json
{
    "videoUrls": ["https://www.tiktok.com/@scout2015/video/6718335390845095173"],
    "mode": "interval",
    "intervalSeconds": 0.5,
    "startTime": "0:02",
    "endTime": "0:08",
    "outputFormat": "webp"
}
```

#### Screenshots at exact times

```json
{
    "videoUrls": ["https://youtu.be/dQw4w9WgXcQ"],
    "mode": "timestamps",
    "timestamps": ["0:43", "1m30s", "00:02:15.500"],
    "maxWidth": 0,
    "outputFormat": "png"
}
```

### Output example

Real rows from a keyframes run on Big Buck Bunny (YouTube, 1:00 to 2:00, October 17, 2026). A frame row:

```json
{
    "recordType": "frame",
    "videoUrl": "https://www.youtube.com/watch?v=aqz-KE-bpKQ",
    "videoTitle": "Big Buck Bunny 60fps 4K - Official Blender Foundation Short Film",
    "videoId": "aqz-KE-bpKQ",
    "platform": "youtube",
    "mode": "keyframes",
    "frameIndex": 4,
    "timestampSec": 68.2,
    "timestamp": "00:01:08.200",
    "sceneScore": null,
    "width": 1280,
    "height": 720,
    "imageFormat": "jpg",
    "kvKey": "v1-aqz-KE-bpKQ-frame-0004.jpg",
    "frameUrl": "https://api.apify.com/v2/key-value-stores/STORE_ID/records/v1-aqz-KE-bpKQ-frame-0004.jpg",
    "durationSec": 635,
    "proxyUsed": "residential"
}
```

The video summary row:

```json
{
    "recordType": "video",
    "status": "ok",
    "videoUrl": "https://www.youtube.com/watch?v=aqz-KE-bpKQ",
    "videoTitle": "Big Buck Bunny 60fps 4K - Official Blender Foundation Short Film",
    "videoId": "aqz-KE-bpKQ",
    "platform": "youtube",
    "mode": "keyframes",
    "durationSec": 635,
    "framesExtracted": 18,
    "contactSheetUrl": null,
    "transferredMb": 37.8,
    "minutesScanned": 0,
    "proxyUsed": "residential",
    "error": null
}
```

Download the dataset in JSON, HTML, CSV or Excel from the Output tab, or set the input on the [Input tab](https://apify.com/parsebird/video-frame-extractor/input-schema).

### Use Video Frame Extractor from Python or JavaScript

Install the Apify client (`pip install apify-client` or `npm install apify-client`) and use your [API token](https://console.apify.com/settings/integrations).

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("<APIFY_TOKEN>")

run = client.actor("parsebird/video-frame-extractor").call(run_input={
    "videoUrls": ["https://www.youtube.com/watch?v=aqz-KE-bpKQ"],
    "mode": "interval",
    "intervalSeconds": 10,
    "maxWidth": 640,
})

store = client.key_value_store(run["defaultKeyValueStoreId"])
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    if row["recordType"] == "frame":
        image = store.get_record(row["kvKey"])["value"]
        with open(row["kvKey"], "wb") as fh:
            fh.write(image)
        print(row["timestamp"], row["kvKey"])
```

#### JavaScript

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

const client = new ApifyClient({ token: '<APIFY_TOKEN>' });

const run = await client.actor('parsebird/video-frame-extractor').call({
    videoUrls: ['https://www.tiktok.com/@scout2015/video/6718335390845095173'],
    mode: 'count',
    frameCount: 6,
    contactSheet: true,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.filter((r) => r.recordType === 'frame').forEach((f) => console.log(f.timestamp, f.frameUrl));
console.log('Contact sheet:', items.find((r) => r.recordType === 'video')?.contactSheetUrl);
```

### Use cases

- **Thumbnails and previews**: pull a handful of clean frames from each video for a catalog, CMS or social post.
- **Storyboards and ad breakdowns**: scenes mode gives one frame per shot of a trailer, commercial or music video.
- **Image datasets for AI**: interval mode turns video into evenly spaced training or evaluation images, ready for captioning or labeling.
- **Visual search and indexing**: store keyframes or scene frames next to a transcript to make a video library searchable.
- **Content review and moderation**: check what appears in a batch of TikToks or Reels without watching each one.
- **Tutorials and documentation**: grab the exact moments of a screen recording at the timestamps you already know.

### How it works

The Actor reads each link with [yt-dlp](https://github.com/yt-dlp/yt-dlp) or, for Instagram and Facebook, with its own logged-out page reader, and picks the smallest video stream that is at least as wide as **Max frame width**. [ffmpeg](https://ffmpeg.org/) then seeks to each frame's time and decodes only from the nearest keyframe, so a frame usually needs one short piece of the video rather than the whole file. When frames are 3 seconds apart or closer, one pass through the chosen part of the video is cheaper and is used instead. Scenes and keyframes modes read the whole chosen time range at the lowest available quality, then fetch each selected frame at your chosen width.

### How much does it cost to extract frames from a video?

Video Frame Extractor uses pay-per-event pricing. Platform usage (compute and storage) is included in the event prices; you only pay for the events below.

| Event | What it counts | Free | Bronze | Silver | Gold |
|-------|----------------|------|--------|--------|------|
| Frame | One still frame saved as an image | $0.00199 | $0.00179 | $0.00159 | $0.00139 |
| Video processed | Each video opened and processed | $0.00999 | $0.00949 | $0.00899 | $0.00849 |
| Minute scanned | Each started minute of video scanned in scenes mode | $0.00499 | $0.00479 | $0.00459 | $0.00439 |
| Megabyte downloaded | Each megabyte fetched through a residential proxy, when a site blocks the faster routes | $0.049 | $0.047 | $0.045 | $0.043 |

Videos that fail, or that are skipped for going over the download limit, are not charged.

Examples on the Free plan:

- **10 frames from one video** over a direct or datacenter connection: $0.00999 + 10 × $0.00199 = **about $0.03**.
- **Scenes mode on a 10-minute video, 30 frames kept**: $0.00999 + 10 × $0.00499 + 30 × $0.00199 = **about $0.12**.
- **Residential traffic adds up**: in our October 17, 2026 tests, YouTube sometimes refused the direct and datacenter routes. One run of 10 frames at 1280 px from a 4K, 60 fps YouTube video then fetched 28.7 MB through the residential proxy, about $1.42 in megabyte charges. Interval and count runs with frames close together are much cheaper (40 frames at 640 px, one per second over 40 seconds, fetched 2.3 MB through the residential proxy).

To keep costs down, lower **Max frame width** (fewer megabytes per frame), set **Proxy mode** to Direct or Datacenter if you'd rather have a blocked video fail than pay for residential traffic, and use **Max download per video** as a hard cap. The run also stops at the maximum cost per run you set in Apify Console; frames are cut to fit the remaining budget.

### Is it legal to extract frames from online videos?

This Actor only reads videos that are publicly available without logging in, the same way a viewer's browser does, and saves stills from them. Extracting frames is generally fine for analysis, indexing and personal use, but the frames remain part of the original work: you are responsible for following each platform's terms of service and copyright law, especially if you republish frames. If you aren't sure, consult a lawyer. Read more on the [Apify blog about web scraping legality](https://blog.apify.com/is-web-scraping-legal/).

This Actor is unofficial and isn't affiliated with, endorsed by or sponsored by YouTube, TikTok, Meta or X.

### Other video tools from ParseBird

- [YouTube Thumbnail Downloader](https://apify.com/parsebird/youtube-thumbnail-downloader): download YouTube thumbnails in bulk at the best available quality.
- [YouTube Shorts Downloader](https://apify.com/parsebird/youtube-shorts-downloader): direct media links, title, channel and stats for YouTube Shorts.
- [TikTok Video Downloader](https://apify.com/parsebird/tiktok-video-downloader): save TikTok videos as MP4 with permanent download links.
- [Video & Audio Transcriber](https://apify.com/parsebird/video-audio-transcriber): transcribe videos and podcasts from 1,800+ sites with Whisper.
- [YouTube Transcript Scraper](https://apify.com/parsebird/youtube-transcript-scraper): YouTube transcripts and subtitles as text, SRT or VTT.

### FAQ

**Which links work?**
YouTube videos and Shorts, TikTok videos, Instagram reels and video posts, Facebook videos, reels and fb.watch links, X posts with video, other sites that [yt-dlp supports](https://github.com/yt-dlp/yt-dlp/blob/master/supportedsites.md), and direct links to video files and HLS (.m3u8) streams. Content has to be public: private, members-only, age-restricted and login-only videos fail with a clear error and are not charged. Live streams aren't supported.

**Does it download the whole video?**
Not for count, interval and timestamps modes: it seeks to each frame and fetches only the nearby part of the video. Scenes and keyframes modes read the whole time range you pick, at the lowest quality the site offers.

**Why does a frame look a little earlier or later than I expected?**
Videos are made of individual frames, so each time is matched to the frame shown at that moment. In scenes mode the frame is taken right at the cut, so it shows the first frame of the new shot.

**Why is the first frame in scenes mode missing a score?**
Scenes mode always includes the opening frame of the chosen range so the storyboard starts at the beginning. It isn't a shot change, so its `sceneScore` is empty.

**Why was a video skipped?**
Either the run reached your maximum cost, or the video needed more data than **Max download per video**. Skipped videos are free. Raise the limit, lower **Max frame width**, or shorten the time range.

**Where are the images?**
In the run's default key-value store. Each frame row has `frameUrl` (a direct link) and `kvKey` (the record key). You can also list all keys in the **Storage** tab of the run.

**Can I use it through the API?**
Yes. Use the [API tab](https://apify.com/parsebird/video-frame-extractor/api) or the Python and JavaScript examples above. You can also run it from Make, Zapier or n8n.

**Something is missing or broken?**
Open an issue on the [Issues tab](https://apify.com/parsebird/video-frame-extractor/issues).

# Changelog

This Actor's version history is a separate document: https://apify.com/parsebird/video-frame-extractor/changelog.md

# Actor input Schema

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

Add links to the videos to extract frames from: YouTube videos and Shorts, TikTok, Instagram reels and posts, Facebook videos and reels, X posts, other sites supported by yt-dlp, and direct video files (MP4, WebM, MOV, M3U8). Up to 100 links per run.

## `mode` (type: `string`):

Choose how frames are picked. <b>Count</b>: N frames spread evenly across the video. <b>Interval</b>: one frame every N seconds. <b>Scenes</b>: one frame at each shot change. <b>Keyframes</b>: the video's own keyframes (I-frames). <b>Timestamps</b>: the exact times you list.

## `frameCount` (type: `integer`):

Count mode: how many frames to take. Each one comes from the middle of an equal slice of the video, which avoids black lead-in and fade-out frames.

## `intervalSeconds` (type: `number`):

Interval mode: seconds between frames, starting at the start time. 0.5 gives two frames per second.

## `sceneThreshold` (type: `number`):

Scenes mode: how different two consecutive frames must be to count as a new shot, from 0.01 to 0.99. Lower finds more scenes (0.2 catches soft cuts), higher finds only hard cuts (0.5).

## `timestamps` (type: `array`):

Timestamps mode: the times to capture. Seconds (90 or 90.5), clock format (1:30, 00:01:30.250) or 1m30s all work. Times past the end of a video are ignored.

## `startTime` (type: `string`):

Optional. Ignore everything before this time, e.g. 30, 0:30 or 1m. Applies to every mode except timestamps.

## `endTime` (type: `string`):

Optional. Ignore everything after this time, e.g. 300, 5:00 or 5m. Leave empty to run to the end. Applies to every mode except timestamps.

## `maxFramesPerVideo` (type: `integer`):

Upper limit on frames per video in every mode. In scenes mode the strongest scene changes are kept, in keyframes mode the keyframes are sampled evenly, and in interval mode the first frames are kept.

## `outputFormat` (type: `string`):

File format of the saved frames. JPG is smallest and universal, PNG is lossless, WebP is small with high quality.

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

Scale frames down to at most this width, keeping the aspect ratio; frames are never scaled up. The smallest source quality that reaches this width is downloaded, which keeps runs fast. 0 = original resolution (best quality available).

## `contactSheet` (type: `boolean`):

Also save one grid image per video with its frames (up to 100) side by side, each stamped with its timestamp. The link is in the video summary row.

## `contactSheetColumns` (type: `integer`):

Number of frames per row on the contact sheet.

## `proxyMode` (type: `string`):

<b>Auto</b> (default) tries a direct connection first, then the Apify datacenter proxy, then a residential proxy, moving on only when the site blocks the faster route. Video data fetched through the residential proxy is billed per MB; the other routes cost nothing extra. Pick a single route only if you need to force one.

## `maxDownloadMbPerVideo` (type: `integer`):

Safety limit on video data fetched per video. Seeking to a frame usually needs well under 1 MB; scenes and keyframes modes read the whole video at its lowest quality. A video that goes over is skipped free of charge. 0 = no limit.

## Actor input object example

```json
{
  "videoUrls": [
    "https://media.w3.org/2010/05/sintel/trailer.mp4"
  ],
  "mode": "count",
  "frameCount": 10,
  "intervalSeconds": 5,
  "sceneThreshold": 0.3,
  "maxFramesPerVideo": 100,
  "outputFormat": "jpg",
  "maxWidth": 1280,
  "contactSheet": false,
  "contactSheetColumns": 5,
  "proxyMode": "auto",
  "maxDownloadMbPerVideo": 500
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

## `images` (type: `string`):

No description

# 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://media.w3.org/2010/05/sintel/trailer.mp4"
    ],
    "mode": "count"
};

// Run the Actor and wait for it to finish
const run = await client.actor("parsebird/video-frame-extractor").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://media.w3.org/2010/05/sintel/trailer.mp4"],
    "mode": "count",
}

# Run the Actor and wait for it to finish
run = client.actor("parsebird/video-frame-extractor").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://media.w3.org/2010/05/sintel/trailer.mp4"
  ],
  "mode": "count"
}' |
apify call parsebird/video-frame-extractor --silent --output-dataset

```

## MCP server setup

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

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/ZjtK1GQnMQASO8t7P/builds/weYu3kxjuzteO7Eyt/openapi.json
