# YouTube Playlist Scraper — Public Video Metadata (`khadinakbar/youtube-playlist-scraper`) Actor

Extract public YouTube playlist videos in order. Use for course, content, and competitor research; returns video IDs, titles, channels, durations, thumbnails, and source URLs. Not for private playlists or video downloads. $0.005 per saved video plus a $0.00005 start event.

- **URL**: https://apify.com/khadinakbar/youtube-playlist-scraper.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** Social media, Automation, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 playlist video saveds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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

## YouTube Playlist Scraper — Public Video Metadata

Extract the ordered videos from public YouTube playlists into structured, exportable records. It is designed for creators, content strategists, researchers, and AI workflows that need a clean list of a course, competitor series, or curated collection—not video downloads, private data, or channel-wide crawling.

### What it returns

Each dataset row represents one public playlist entry.

| Field                                              | Meaning                                                        |
| -------------------------------------------------- | -------------------------------------------------------------- |
| `playlistId`, `playlistTitle`, `playlistOwnerName` | Public playlist identity and context                           |
| `videoId`, `videoUrl`, `position`, `title`         | Ordered video identity and public watch link                   |
| `channelName`, `channelUrl`                        | Public source channel when returned                            |
| `durationText`, `durationSeconds`, `thumbnailUrl`  | Lightweight media metadata                                     |
| `viewCountText`, `publishedText`                   | Values shown by YouTube when included in the playlist response |
| `isPlayable`                                       | Whether YouTube exposed a usable public video reference        |
| `source`, `scrapedAt`                              | Extraction route and freshness timestamp                       |

Use it for public course inventories, content-gap analysis, playlist-to-spreadsheet exports, or as a seed list for a separate public-video enrichment workflow. Do not use it for private playlists, personal data, downloading video/audio, comments, transcripts, or playlist discovery from a channel.

### Input

Pass full public playlist URLs, watch URLs that include `list=`, or raw playlist IDs. The actor deduplicates inputs and applies `maxResults` across the entire run.

```json
{
  "playlists": [
    "https://www.youtube.com/playlist?list=PL590L5WQmH8fJ54F369BLDSqIwcs-TCfs"
  ],
  "maxResults": 25,
  "includeUnavailable": false
}
```

`maxResults` is a strict 1–500 cap. `includeUnavailable` preserves entries that YouTube publicly labels as deleted, private, or unavailable when they are returned; it does not grant access to their content.

### Example output

```json
{
  "playlistId": "PL590L5WQmH8fJ54F369BLDSqIwcs-TCfs",
  "playlistUrl": "https://www.youtube.com/playlist?list=PL590L5WQmH8fJ54F369BLDSqIwcs-TCfs",
  "playlistTitle": "Year in Search",
  "playlistOwnerName": "Google",
  "videoId": "KIViy7L_lo8",
  "videoUrl": "https://www.youtube.com/watch?v=KIViy7L_lo8&list=PL590L5WQmH8fJ54F369BLDSqIwcs-TCfs",
  "title": "2016 — Year in Search",
  "position": 1,
  "channelName": "Google",
  "durationText": "2:01",
  "durationSeconds": 121,
  "thumbnailUrl": "https://i.ytimg.com/vi/KIViy7L_lo8/hqdefault.jpg",
  "isPlayable": true,
  "source": "scrapecreators",
  "scrapedAt": "2026-07-22T00:00:00.000Z"
}
```

Null fields mean YouTube did not expose a stable public value for that entry. The actor never invents missing metadata.

### Pricing and cost cap

This actor is configured for Pay per event. It charges:

- $0.00005 when valid input is accepted and public extraction starts.
- $0.005 for each validated video row that is persisted.

Apify platform usage is additional when the live actor is configured with Pay per event + usage. The run status message shows the maximum event-charge estimate before requests begin; `maxResults: 25` has an event-charge ceiling of $0.12505, plus platform usage. A video is never billed unless its complete validated row is saved.

### Reliability and sources

The primary route uses the documented ScrapeCreators public playlist endpoint when the owner-managed `SCRAPECREATORS_API_KEY` secret is configured. If that provider route is unavailable, the actor attempts YouTube’s public playlist payload and its continuation tokens without requiring user credentials. Both routes normalize into the same schema; `source` identifies which one supplied each record.

If neither route can return useful public data, the run fails honestly as `UPSTREAM_FAILED` rather than reporting an empty success. Private or restricted playlists remain out of scope. YouTube can change public response shapes, so release evidence should include separate short and long public playlist canaries, pagination, unavailable-entry handling, invalid inputs, and fallback routing.

### Terminal outcomes

Every terminal path writes `OUTPUT` and `RUN_SUMMARY` in the default key-value store.

- `COMPLETE`: all accepted public playlist work succeeded.
- `PARTIAL`: useful videos were saved, with skipped input, upstream, validation, or billing-limit warnings.
- `VALID_EMPTY`: valid public input produced no playlist entries.
- `INVALID_INPUT`: no valid public playlist target or an invalid result cap was supplied.
- `UPSTREAM_FAILED`: no useful output was produced because all available public routes failed.
- `CONFIG_ERROR`: deployment configuration prevented the advertised work.

The first four terminal outcomes succeed; the last two deliberately fail so downstream automations can distinguish an upstream outage from an empty playlist.

### API example

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor("khadinakbar/youtube-playlist-scraper").call({
  playlists: [
    "https://www.youtube.com/playlist?list=PL590L5WQmH8fJ54F369BLDSqIwcs-TCfs",
  ],
  maxResults: 25,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Agent prompt card

> Extract the public videos from this YouTube playlist in order. Return video ID, title, channel, duration, thumbnail, and watch URL. Cap the output at 25 videos and report if the playlist is private, unavailable, or only partially retrieved.

### Responsible use

Use only publicly available metadata in a manner consistent with YouTube’s terms, privacy expectations, and applicable law. Do not use this actor to access private/restricted content, collect personal data, or automate spam.

# Actor input Schema

## `playlists` (type: `array`):

Public YouTube playlist URLs or raw playlist IDs to extract, for example 'https://www.youtube.com/playlist?list=PL590L5WQmH8fJ54F369BLDSqIwcs-TCfs' or 'PL590L5WQmH8fJ54F369BLDSqIwcs-TCfs'. The actor deduplicates entries and accepts watch URLs only when they include a list parameter. NOT for channels, private playlists, individual video metadata, or downloads.

## `maxResults` (type: `integer`):

Maximum number of validated playlist-video rows saved across this whole run, for example 25. Choose an integer from 1 to 500; the default is 25, and the actor never charges for more saved videos than this cap. NOT a per-playlist limit or a request-concurrency setting.

## `includeUnavailable` (type: `boolean`):

Include playlist entries that YouTube labels as private, deleted, or otherwise unavailable when they are present in the public response. Defaults to false because these entries can lack a video ID, duration, channel, or watch URL. NOT a way to access private video content.

## Actor input object example

```json
{
  "playlists": [
    "https://www.youtube.com/playlist?list=PL590L5WQmH8fJ54F369BLDSqIwcs-TCfs"
  ],
  "maxResults": 25,
  "includeUnavailable": false
}
```

# Actor output Schema

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

Validated public YouTube playlist-video rows in playlist order.

## `runSummary` (type: `string`):

Detailed outcome, counts, source routing, and billing telemetry.

## `output` (type: `string`):

Compact machine-readable terminal outcome.

# 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 = {
    "playlists": [
        "https://www.youtube.com/playlist?list=PL590L5WQmH8fJ54F369BLDSqIwcs-TCfs"
    ],
    "maxResults": 25,
    "includeUnavailable": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/youtube-playlist-scraper").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 = {
    "playlists": ["https://www.youtube.com/playlist?list=PL590L5WQmH8fJ54F369BLDSqIwcs-TCfs"],
    "maxResults": 25,
    "includeUnavailable": False,
}

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/youtube-playlist-scraper").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "playlists": [
    "https://www.youtube.com/playlist?list=PL590L5WQmH8fJ54F369BLDSqIwcs-TCfs"
  ],
  "maxResults": 25,
  "includeUnavailable": false
}' |
apify call khadinakbar/youtube-playlist-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=khadinakbar/youtube-playlist-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/MwjmaAmNqvjO2D47W/builds/ZE3HT6pMooQU8qUiV/openapi.json
