# Twitch Public Video Downloader (`automation-lab/twitch-public-video-downloader`) Actor

Download authorized public Twitch videos and clips as stored files with creator, timestamps, duration, quality, provenance, and retrieval status.

- **URL**: https://apify.com/automation-lab/twitch-public-video-downloader.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Videos
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Twitch Public Video Downloader

Download authorized, anonymously playable **Twitch videos** and clips from supplied public URLs.
The Actor stores the selected media in the run key-value store and writes typed provenance records to the default dataset.

It supports:

- public Twitch VOD URLs such as `https://www.twitch.tv/videos/{id}`;
- public Twitch clip URLs on `twitch.tv/{channel}/clip/{slug}`;
- short public clip URLs on `clips.twitch.tv/{slug}`;
- complete MP4 clip downloads;
- duration-bounded HLS VOD downloads as MPEG transport streams;
- metadata-only exports when no media file is needed.

No Twitch account, user OAuth token, browser, or proxy is required for anonymously playable media.
Private, removed, subscriber-only, region-restricted, encrypted, or otherwise unavailable media is not bypassed.

### What does this Twitch video downloader do?

For each supplied URL, the Actor validates the Twitch URL, resolves public metadata, selects a video rendition, and optionally streams media into the run's key-value store.

Each successful dataset row includes:

- Twitch VOD or clip identity;
- title and creator identity;
- creation and publication timestamps;
- full media duration;
- downloaded duration for bounded VOD assets;
- public view count and VOD category when available;
- selected resolution and frame rate;
- stored-file key, API URL, size, and format;
- canonical source URL and retrieval status.

Clip files are MP4.
VOD files are assembled from complete public HLS segments and stored as `.ts` files.

### Who is it for?

**Creators and channel teams** can back up authorized public clips and bounded VOD sections with stable provenance metadata.

**Media archivists** can schedule recurring runs and send file links plus source records to an archive pipeline.

**Editors and researchers** can fetch a lower-resolution working copy without manually navigating the Twitch player.

**Data engineers** can export metadata-only rows to datasets, spreadsheets, warehouses, or webhooks.

Only download media you own or have permission to archive.

### Why use this Actor?

- One input accepts both VOD and clip URLs.
- Media is stored with the same run that produced its provenance row.
- Quality, duration, byte limits, item limits, and retries are explicit.
- Metadata-only mode avoids unnecessary media transfer.
- Duplicate URLs in one run are processed once.
- Failed URLs produce diagnostic rows but are not charged as successful items.
- There is no hidden residential proxy fallback.

The Actor does not search Twitch channels or discover videos by keyword.
Supply exact public media URLs.

### Input parameters

| Field | Type | Default | Description |
|---|---:|---:|---|
| `startUrls` | array | required | One to 25 public Twitch VOD or clip URLs. |
| `maxItems` | integer | URL count | Maximum unique URLs to process, from 1 to 25. |
| `downloadMedia` | boolean | `true` | Store media when enabled; export metadata only when disabled. |
| `quality` | string | `480p` | `best`, `1080p`, `720p`, `480p`, `360p`, or `worst`. |
| `maxDurationSeconds` | integer | `15` | Maximum VOD media duration, from 1 to 21,600 seconds. Clips remain complete. |
| `maxMediaSizeMb` | integer | `20` | Per-file safety limit, from 1 to 100 MB. |
| `maxRequestRetries` | integer | `2` | Transient request retries, from 0 to 5. |

If the requested resolution does not exist, the Actor chooses the closest available rendition at or below it.
If every rendition is higher, it chooses the lowest available rendition.

### Getting started

1. Open the Actor input page.
2. Add one or more public Twitch VOD or clip URLs.
3. Keep **Download media** enabled for files, or disable it for metadata only.
4. Select the desired quality.
5. For a VOD, choose the maximum duration to store.
6. Set a byte limit appropriate for the expected media.
7. Start the run.
8. Open **Dataset** for records and **Storage** for downloaded files.

Start with a short clip or a 15-second VOD sample when validating a new workflow.
Increase duration and file limits only after checking output size and cost.

### Example input: download a public clip

```json
{
  "startUrls": [
    { "url": "https://clips.twitch.tv/SmokyFragileFoxRedCoat-MRH2eCK-8aE8xUzd" }
  ],
  "maxItems": 1,
  "downloadMedia": true,
  "quality": "360p",
  "maxMediaSizeMb": 100
}
```

This path stores the complete selected MP4 rendition.

### Example input: export VOD metadata only

```json
{
  "startUrls": [
    { "url": "https://www.twitch.tv/videos/2850006339" }
  ],
  "maxItems": 1,
  "downloadMedia": false,
  "quality": "480p"
}
```

Metadata-only mode still resolves current public title, creator, duration, category, thumbnail, and view count.
It does not create a media file.

### Example input: archive a bounded VOD sample

```json
{
  "startUrls": [
    { "url": "https://www.twitch.tv/videos/2850006339" }
  ],
  "downloadMedia": true,
  "quality": "360p",
  "maxDurationSeconds": 15,
  "maxMediaSizeMb": 100,
  "maxRequestRetries": 2
}
```

The Actor stores complete HLS segments whose total duration fits the requested bound.
Because Twitch segment lengths vary, the resulting duration can be slightly below the exact limit.

### Output fields

| Field | Meaning |
|---|---|
| `mediaType` | `video` or `clip`. |
| `twitchId` | Twitch VOD ID or clip ID. |
| `title` | Public media title. |
| `creatorId` | Twitch broadcaster ID. |
| `creatorLogin` | Broadcaster login. |
| `creatorName` | Broadcaster display name. |
| `createdAt` | Twitch creation timestamp. |
| `publishedAt` | Publication timestamp when available. |
| `durationSeconds` | Full source duration. |
| `downloadedDurationSeconds` | Duration represented by the stored asset. |
| `viewCount` | Public view count at retrieval time. |
| `game` | VOD category or game when available. |
| `thumbnailUrl` | Twitch preview image. |
| `sourceUrl` | Canonical public Twitch page. |
| `format` | `mp4` for clips or `ts` for stored VOD media. |
| `resolution` | Selected Twitch rendition label. |
| `frameRate` | Selected frame rate when available. |
| `storedFileKey` | Key-value store record key. |
| `storedFileUrl` | Apify API URL for the file. |
| `storedFileSizeBytes` | Stored file size. |
| `retrievalStatus` | `downloaded`, `partial`, `metadata_only`, or `failed`. |
| `error` | Concise failure reason, otherwise `null`. |
| `retrievedAt` | Record production timestamp. |

Fields can be null when Twitch does not expose the value or when an input fails.

### Example output

```json
{
  "mediaType": "clip",
  "twitchId": "ExampleClipSlug123",
  "title": "Example stream highlight",
  "creatorId": "123456789",
  "creatorLogin": "examplechannel",
  "creatorName": "Example Channel",
  "createdAt": "2026-01-15T12:00:00.000Z",
  "publishedAt": "2026-01-15T12:00:00.000Z",
  "durationSeconds": 29,
  "downloadedDurationSeconds": 29,
  "viewCount": 1500,
  "game": null,
  "thumbnailUrl": "https://static-cdn.jtvnw.net/example-thumbnail.jpg",
  "sourceUrl": "https://clips.twitch.tv/ExampleClipSlug123",
  "format": "mp4",
  "resolution": "360p",
  "frameRate": 30,
  "storedFileKey": "twitch-clip-ExampleClipSlug123-360p.mp4",
  "storedFileUrl": "https://api.apify.com/v2/key-value-stores/exampleStore/records/twitch-clip-ExampleClipSlug123-360p.mp4",
  "storedFileSizeBytes": 2852913,
  "retrievalStatus": "downloaded",
  "error": null,
  "retrievedAt": "2026-01-15T12:01:00.000Z"
}
```

The dataset record is the durable integration contract.
Playback authorization and CDN URLs are intentionally not exposed because they are short-lived.

### Where are downloaded files stored?

Downloaded files are records in the run's default key-value store.
Use `storedFileUrl` from the dataset row to retrieve a file through the Apify API.

- `twitch-clip-*.mp4` contains a complete selected clip rendition.
- `twitch-video-*.ts` contains the selected VOD HLS segments.

Storage retention follows your Apify account and storage settings.
Copy important files to your long-term object storage before retention expires.

### How much does it cost to download Twitch videos?

The Actor uses pay-per-event pricing:

- **Start:** `$0.005` once per run.
- **Twitch media record:** each successful metadata or download record uses tiered pricing; the FREE-tier rate is `$0.0088228` per item and BRONZE is `$0.007672`.

Downloaded and metadata-only records use the same item event.
Failed and duplicate inputs are not charged as successful items.

At FREE-tier rates, a one-record run costs about `$0.0138` including the run start, whether it stores a file or returns metadata only.
A five-record run costs about `$0.0491` at FREE-tier rates.
Higher subscription tiers receive the active tier discounts shown on the Actor pricing page.

### Limits and expected behavior

- A run accepts at most 25 supplied URLs.
- A VOD download is limited to complete HLS segments within `maxDurationSeconds`.
- A file that exceeds `maxMediaSizeMb` is rejected and removed rather than stored partially by bytes.
- Clip media is downloaded in full or rejected.
- Public metadata and playback availability can change between runs.
- Stored VOD files are MPEG transport streams, not remuxed MP4 files.
- The Actor does not combine separate audio/video tracks or transcode media.
- The Actor does not bypass login, subscription, DRM, geographic, or rights restrictions.
- A stored file is capped at 100 MB; long or high-resolution VODs may need a shorter duration or lower rendition.

A `partial` status for a VOD is expected when its full duration exceeds `maxDurationSeconds`.
A `failed` status includes a concise error suitable for retry classification.

### Retry and failure behavior

The Actor retries only transient network errors, HTTP 429 responses, and server failures.
Retry delay increases between attempts.

It does not blindly retry:

- malformed or unsupported URLs;
- a Twitch media ID that no longer exists;
- private or subscriber-only media;
- anonymous playback denial;
- encrypted media;
- a deterministic file-size violation.

If every supplied URL fails, the run exits as failed instead of reporting a misleading successful empty run.
Mixed runs preserve diagnostic rows for failed URLs and useful records for successful ones.

### Scheduling an archival workflow

Use an Apify schedule when you maintain a known list of authorized media URLs.
A practical workflow is:

1. Keep the exact Twitch URLs in Task input.
2. Run metadata-only checks frequently.
3. Trigger media downloads only for newly approved URLs.
4. Export dataset records to a table or warehouse.
5. Copy stored files to long-term storage.
6. Deduplicate downstream by `mediaType` plus `twitchId`.

The Actor does not discover newly published channel media.
Pair it with a separate URL-discovery process if discovery is required.

### Integrations

Use Apify integrations to send records to:

- Google Sheets for a lightweight archive index;
- webhooks for downstream file transfer;
- Make or Zapier for approval workflows;
- cloud storage automation;
- a database or data warehouse;
- another Actor through a Task or API workflow.

Always pass exact authorized Twitch URLs into this Actor.

### Run with the Apify API using cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~twitch-public-video-downloader/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "startUrls": [{"url": "https://clips.twitch.tv/SmokyFragileFoxRedCoat-MRH2eCK-8aE8xUzd"}],
    "downloadMedia": true,
    "quality": "360p",
    "maxMediaSizeMb": 100
  }'
```

Use the returned run ID to inspect status, dataset items, and key-value store records.
Do not place an Apify token in source control.

### Run with JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/twitch-public-video-downloader').call({
  startUrls: [
    { url: 'https://www.twitch.tv/videos/2850006339' },
  ],
  downloadMedia: false,
  maxItems: 1,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

For media downloads, read `storedFileUrl` from each successful item.

### Run with Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("automation-lab/twitch-public-video-downloader").call(
    run_input={
        "startUrls": [
            {"url": "https://www.twitch.tv/videos/2850006339"}
        ],
        "downloadMedia": False,
        "maxItems": 1,
    }
)

items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)
```

The Python client can also fetch key-value store records after a download run.

### Use through MCP

Add the Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/twitch-public-video-downloader"
```

#### Claude Desktop

Add this server configuration to Claude Desktop:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/twitch-public-video-downloader"
    }
  }
}
```

#### Cursor

Use the same MCP server URL in Cursor's MCP settings and authenticate with your Apify account when prompted.

#### VS Code

Add the same HTTP MCP server URL to your VS Code MCP configuration. Keep tokens in the editor's secure environment rather than in the workspace file.

Example prompts:

- "Export metadata for this public Twitch VOD without downloading the file."
- "Download this authorized public Twitch clip at up to 360p."
- "Store the first 30 seconds of this public Twitch VOD and return its provenance row."

Include the exact URL and explicit download limits in an MCP request.

### Responsible and legal use

Twitch media can be protected by copyright, contract, privacy, publicity, and platform rules.
Use this Actor only for media you own, control, or are authorized to download and archive.

Do not use it to:

- redistribute media without permission;
- bypass access controls or subscriptions;
- archive private or restricted content;
- evade geographic or rights limitations;
- violate Twitch terms or applicable law.

You are responsible for your inputs, storage, retention, and downstream use.
The Actor deliberately fails closed when anonymous public playback is unavailable.

### FAQ and troubleshooting

#### Why did my VOD return `partial`?

`maxDurationSeconds` was shorter than the full VOD.
Increase the duration if you are authorized to archive more, and ensure the byte limit is sufficient.

#### Why did the file-size check fail?

The selected rendition exceeded `maxMediaSizeMb`.
Choose a lower quality, reduce VOD duration, or raise the size limit within the supported maximum.

#### Why does a Twitch URL fail even though the page once worked?

Twitch VODs and clips can be removed, expire, become restricted, or lose anonymous playback availability.
Confirm the URL still plays while logged out.

#### Why is a VOD file `.ts` instead of `.mp4`?

Public Twitch VOD playback uses HLS segments.
The Actor joins complete selected segments without transcoding, preserving a low-memory streaming path.
Use a media tool you trust to remux the authorized file when MP4 is required.

#### Does it download live streams?

No.
This Actor supports supplied public VOD and clip URLs, not active live channels.

#### Does it search Twitch?

No.
Use exact media URLs.

### Related Actors

- [Twitch Scraper](https://apify.com/automation-lab/twitch-scraper) for public Twitch channel, stream, game, and clip metadata workflows.
- [M3U8 Playlist Downloader](https://apify.com/automation-lab/m3u8-playlist-downloader) for authorized public HLS playlists you already possess.
- [Reddit Public Video Downloader](https://apify.com/automation-lab/reddit-public-video-downloader) for authorized Reddit-hosted video archives.

These Actors solve separate source or discovery jobs.
Use only the tool whose source and access scope match your workflow.

# Actor input Schema

## `startUrls` (type: `array`):

Public Twitch VOD URLs such as https://www.twitch.tv/videos/2850006339 and clip URLs on twitch.tv or clips.twitch.tv.

## `maxItems` (type: `integer`):

Maximum number of unique supplied URLs to process.

## `downloadMedia` (type: `boolean`):

Store the selected MP4 clip or bounded HLS VOD media file in the run key-value store. Disable this for metadata-only exports.

## `quality` (type: `string`):

Preferred rendition. The Actor selects the closest available resolution at or below the requested value, or the lowest available rendition when necessary.

## `maxDurationSeconds` (type: `integer`):

Maximum duration of HLS segments to save per VOD. Clips are always downloaded in full. A shorter value creates a playable bounded partial VOD asset.

## `maxMediaSizeMb` (type: `integer`):

Reject a media file if the streamed file exceeds this size limit.

## `maxRequestRetries` (type: `integer`):

Retries for transient network, rate-limit, and server failures. Invalid, private, removed, and subscriber-only media is not retried blindly.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://clips.twitch.tv/SmokyFragileFoxRedCoat-MRH2eCK-8aE8xUzd"
    }
  ],
  "maxItems": 10,
  "downloadMedia": true,
  "quality": "480p",
  "maxDurationSeconds": 15,
  "maxMediaSizeMb": 20,
  "maxRequestRetries": 2
}
```

# Actor output Schema

## `overview` (type: `string`):

Dataset containing media metadata, provenance, retrieval status, and stored-file links.

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

Run key-value store containing downloaded MP4 clip and TS VOD 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 = {
    "startUrls": [
        {
            "url": "https://clips.twitch.tv/SmokyFragileFoxRedCoat-MRH2eCK-8aE8xUzd"
        }
    ],
    "maxItems": 10,
    "downloadMedia": true,
    "quality": "480p",
    "maxDurationSeconds": 15,
    "maxMediaSizeMb": 20,
    "maxRequestRetries": 2
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/twitch-public-video-downloader").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 = {
    "startUrls": [{ "url": "https://clips.twitch.tv/SmokyFragileFoxRedCoat-MRH2eCK-8aE8xUzd" }],
    "maxItems": 10,
    "downloadMedia": True,
    "quality": "480p",
    "maxDurationSeconds": 15,
    "maxMediaSizeMb": 20,
    "maxRequestRetries": 2,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/twitch-public-video-downloader").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 '{
  "startUrls": [
    {
      "url": "https://clips.twitch.tv/SmokyFragileFoxRedCoat-MRH2eCK-8aE8xUzd"
    }
  ],
  "maxItems": 10,
  "downloadMedia": true,
  "quality": "480p",
  "maxDurationSeconds": 15,
  "maxMediaSizeMb": 20,
  "maxRequestRetries": 2
}' |
apify call automation-lab/twitch-public-video-downloader --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/twitch-public-video-downloader"
        }
    }
}

```

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/GXXLivwHBWGtpK9vv/builds/uNMXMkRadvYTiEmgH/openapi.json
