# YouTube Playlist Scraper (`thenetaji/youtube-playlist-scraper`) Actor

Collect playlist metadata and every available video from one or many YouTube playlist URLs or IDs. Paginate automatically and optionally add full video details or timed transcripts.

- **URL**: https://apify.com/thenetaji/youtube-playlist-scraper.md
- **Developed by:** [The Netaji](https://apify.com/thenetaji) (community)
- **Categories:** Social media, Videos, For creators
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.45 / 1,000 results

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/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

The Actor reads one or many public YouTube playlists and returns every video in them, with the playlist's own metadata attached to each row. It can optionally add full video details or a timed transcript to each item. Playlists are accepted as URLs or bare playlist IDs. No YouTube account, API key, or cookie is required.

### Accepted input

| Field | Type | Default | Description |
|---|---|---|---|
| `playlist_sources` | array | — | Required. Playlist URLs or playlist IDs. |
| `maxItems` | integer | `100` | Maximum videos saved across all playlists. `0` removes the limit. |
| `includeVideoDetails` | boolean | `false` | Attaches the full video record to each item. |
| `includeTranscript` | boolean | `false` | Attaches the timed transcript to each item. |
| `region_code` | string | `US` | Two-letter country code used to localize results. |
| `language_code` | string | `en` | Language code for result text and transcript selection. |

```json
{
  "playlist_sources": [
    { "url": "https://www.youtube.com/playlist?list=PLMC9KNkIncKtPzgY-5rmhvj7fax8fdxoj" }
  ],
  "maxItems": 200,
  "includeVideoDetails": false
}
```

### Response fields

One row per video in the playlist.

| Field | Contents |
|---|---|
| `recordType` | Always `playlist_video` |
| `source` | The playlist URL or ID as supplied |
| `type` | YouTube's own label for the item |
| `videoId` | Video ID |
| `title`, `description` | Video text |
| `url` | Canonical video URL, derived from the ID |
| `viewCount`, `viewCountText` | Numeric and human-readable view counts |
| `lengthText` | Duration |
| `publishedTimeText`, `publishedAt`, `publishDate` | Relative time, ISO 8601 timestamp, and date |
| `thumbnail` | Thumbnail images |
| `position` | One-based position within the run |
| `meta` | The playlist's own metadata, on every row |

`meta` carries the playlist itself — `playlistId`, `title`, `description`, `videoCount`, `viewCount`, `lastUpdated`, and the owning `channelId`, `channelTitle`, and `channelHandle`. Because it is attached to every row, a single playlist's rows are self-describing without a separate lookup.

Present only when the matching enrichment is enabled:

| Field | Contents |
|---|---|
| `videoDetails` | The full video record, as returned by the video endpoint |
| `transcript` | Timed transcript segments |

```json
{
  "recordType": "playlist_video",
  "type": "video",
  "videoId": "ekr2nIex040",
  "title": "ROSÉ & Bruno Mars - APT. (Official Music Video)",
  "url": "https://www.youtube.com/watch?v=ekr2nIex040",
  "viewCount": 2600000000,
  "viewCountText": "2.6B views",
  "lengthText": "2:54",
  "publishDate": "2025-07-30",
  "position": 1
}
```

### Pagination and result limits

Playlist pages are large — a request commonly returns 100 items — and the cursor is followed until `maxItems` is reached or YouTube stops serving pages. `maxItems` is shared across every playlist in the run, so a single long playlist can consume the whole budget before a later one is reached. Run long playlists separately, or set `maxItems: 0`, when complete coverage of each matters.

`meta.videoCount` is the playlist's own declared length, which makes it easy to tell a completed playlist from a truncated run.

### Behaviour on partial results

A target that is not a playlist URL or ID is logged and skipped. A playlist that YouTube declines to serve — private, deleted, or region-blocked — is logged and skipped, and the remaining playlists still run. Rows already collected are kept. The run fails only when no supplied target was a usable playlist reference.

The two enrichments are independent and are applied per item, each costing one extra request. A failure leaves that field absent, is not charged, and does not interrupt the run. On a 200-video playlist, enabling both performs 400 extra requests, so it is worth collecting the playlist first and enriching a shortlist afterwards.

### Frequently asked questions

**Which playlist forms are accepted?**
A full playlist URL, a watch URL carrying a `list=` parameter, or a bare playlist ID. Mixing forms in one run is fine.

**Why did a playlist return fewer videos than its `videoCount`?**
Either `maxItems` was reached, or the playlist contains videos that are no longer public. Deleted and private entries remain in a playlist's declared count but are not served as items, so a small shortfall against `meta.videoCount` is normal and comes from YouTube.

**Can a channel's "all uploads" playlist be read?**
Yes, if you have its ID. The [YouTube Channel Scraper](https://apify.com/thenetaji/youtube-channel-scraper) is usually the better route to a channel's uploads, since it takes a handle or URL and paginates the uploads tab directly.

**What does `includeVideoDetails` add that the playlist row does not have?**
The playlist listing gives title, duration, view count, and publication date. The full record adds the description, tags, category, like and comment counts, caption availability, and the countries the video is playable in. It is one request per item.

**Are private or unavailable videos included as rows?**
No. YouTube does not serve them as playlist items, so they do not appear. Their absence is the difference between `meta.videoCount` and the rows saved.

**Is a YouTube account or API key required?**
No. Only publicly visible playlists are read, with no credentials or logged-in session, and no YouTube Data API quota is consumed.

### Related Actors

| Actor | Purpose |
|---|---|
| [YouTube Video Scraper](https://apify.com/thenetaji/youtube-video-scraper) | Full metadata and transcripts for known videos and Shorts |
| [YouTube Channel Scraper](https://apify.com/thenetaji/youtube-channel-scraper) | Channel details, uploads, playlists, and community posts |
| [YouTube Search Scraper](https://apify.com/thenetaji/youtube-search-scraper) | Find videos by keyword, hashtag, or chart |
| [YouTube Comments Scraper](https://apify.com/thenetaji/youtube-comments-scraper) | Comments from videos, Shorts, and community posts |

# Actor input Schema

## `playlist_sources` (type: `array`):

One or more public YouTube playlist URLs or playlist IDs.

## `includeVideoDetails` (type: `boolean`):

Attach a separate full video-detail record to every eligible playlist item. One extra request per item, charged only when it succeeds.

## `includeTranscript` (type: `boolean`):

Attach timed transcript segments when a transcript is available. One extra request per video, charged only when a transcript is returned.

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

Maximum number of primary records to save across all targets. Set 0 to continue until no more pages remain.

## `region_code` (type: `string`):

Optional two-letter country code used to localize results, such as US, IN, or DE.

## `language_code` (type: `string`):

Optional language code used to localize result text, such as en, es, or pt-BR.

## Actor input object example

```json
{
  "playlist_sources": [
    {
      "url": "https://www.youtube.com/playlist?list=PLMC9KNkIncKtPzgY-5rmhvj7fax8fdxoj"
    }
  ],
  "includeVideoDetails": false,
  "includeTranscript": false,
  "maxItems": 20,
  "region_code": "US",
  "language_code": "en"
}
```

# Actor output Schema

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

Dataset containing all scraped data

# 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 = {
    "playlist_sources": [
        {
            "url": "https://www.youtube.com/playlist?list=PLMC9KNkIncKtPzgY-5rmhvj7fax8fdxoj"
        }
    ],
    "maxItems": 20,
    "region_code": "US"
};

// Run the Actor and wait for it to finish
const run = await client.actor("thenetaji/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 = {
    "playlist_sources": [{ "url": "https://www.youtube.com/playlist?list=PLMC9KNkIncKtPzgY-5rmhvj7fax8fdxoj" }],
    "maxItems": 20,
    "region_code": "US",
}

# Run the Actor and wait for it to finish
run = client.actor("thenetaji/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 '{
  "playlist_sources": [
    {
      "url": "https://www.youtube.com/playlist?list=PLMC9KNkIncKtPzgY-5rmhvj7fax8fdxoj"
    }
  ],
  "maxItems": 20,
  "region_code": "US"
}' |
apify call thenetaji/youtube-playlist-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

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