# YouTube Playlist Videos Scraper (`automation-lab/youtube-playlist-videos-metadata-extractor`) Actor

Extract public YouTube playlist metadata and ordered video records for archiving, monitoring, and content analysis.

- **URL**: https://apify.com/automation-lab/youtube-playlist-videos-metadata-extractor.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Videos, Social media, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.48 / 1,000 video extracteds

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

## YouTube Playlist Videos Scraper

Extract **YouTube playlist videos** in their displayed order, together with playlist identity, owner, description, counts, and useful video metadata.

Supply one or more public playlist URLs or IDs. The Actor returns integration-ready dataset rows for playlist archiving, catalog monitoring, content analysis, and spreadsheet or data-pipeline exports.

No YouTube account, API key, browser automation, or proxy configuration is required.

### What does YouTube Playlist Videos Scraper do?

The Actor resolves each supplied public playlist and exports one row per visible playlist video.

It preserves playlist order and adds the context needed to understand every row:

- canonical playlist and video IDs;
- playlist title, description, owner, public visibility, and displayed counts;
- video title, channel, position, duration, publish timing, and visible views;
- canonical URLs and available thumbnails;
- a retrieval timestamp for repeatable archives.

The default dataset contains only normalized video records. It does not download videos, audio, captions, or thumbnails.

### Who is this YouTube playlist extractor for?

#### Content and editorial teams

Archive a curated playlist, audit its sequence, or feed selected videos into a content calendar.

#### Researchers and analysts

Build ordered datasets for topic, creator, duration, and catalog analysis without manually copying YouTube pages.

#### Learning and development teams

Export course playlists to inspect lesson order, duration, channel ownership, and changes between scheduled runs.

#### Data engineers

Send consistent JSON records to a warehouse, spreadsheet, webhook workflow, or another Apify Actor.

#### Catalog monitors

Run the same input on a schedule and compare `videoId` plus `position` to detect downstream additions, removals, and reorderings.

### Why use this Actor?

- **Ordered output:** every video has a one-based playlist `position`.
- **Playlist context on every row:** no separate join is required for common exports.
- **Multiple playlists:** submit up to 50 playlist URLs or IDs per run.
- **Bounded collection:** set a global `maxItems` limit up to 10,000 records.
- **Pagination:** long playlists are followed through YouTube continuation pages.
- **Stable identities:** canonical IDs and URLs simplify snapshots and comparisons.
- **Low overhead:** direct structured requests avoid video downloads and browser rendering.
- **Pay for useful output:** the per-video event is emitted only for a saved record.

### What YouTube playlist data can I extract?

| Group | Fields | Meaning |
| --- | --- | --- |
| Input provenance | `playlistInput` | Original playlist URL or ID supplied by the user |
| Playlist identity | `playlistId`, `playlistUrl` | Canonical playlist identity and URL |
| Playlist profile | `playlistTitle`, `playlistDescription` | Public title and description |
| Playlist owner | `playlistOwnerName`, `playlistOwnerChannelId`, `playlistOwnerUrl` | Public owner channel context |
| Playlist status | `playlistVisibility` | `public`, confirmed by logged-out retrieval |
| Playlist counts | `playlistVideoCount`, `playlistViewCount` | Counts displayed by YouTube when available |
| Playlist freshness | `playlistLastUpdatedText` | Human-readable last-updated text when exposed |
| Video identity | `videoId`, `videoUrl`, `title` | Canonical video identity and title |
| Playlist membership | `position` | One-based position in playlist order |
| Video channel | `channelName`, `channelId`, `channelUrl` | Public creator channel context |
| Duration | `durationText`, `durationSeconds` | Display duration and normalized seconds |
| Publication | `publishedTimeText` | Human-readable publication timing when exposed |
| Views | `viewCountText`, `viewCount` | Display and normalized view count when exposed |
| Images | `thumbnailUrl`, `thumbnails` | Best thumbnail and available size variants |
| Availability | `isPlayable` | Playlist-row playability when YouTube exposes it |
| Provenance | `retrievedAt` | ISO 8601 retrieval timestamp |

Some metadata is nullable because YouTube does not expose every field for every video, live stream, deleted entry, or playlist layout.

### How to extract a public YouTube playlist

1. Open the Actor in Apify Console.
2. Add one or more public playlist URLs or raw playlist IDs to **Playlist URLs or IDs**.
3. Set **Maximum video records** for the total output you need.
4. Click **Start**.
5. Open the **Dataset** tab to preview or export JSON, CSV, Excel, XML, or RSS.

A minimal input is:

```json
{
  "playlistInputs": [
    "https://www.youtube.com/playlist?list=PLBCF2DAC6FFB574DE"
  ],
  "maxItems": 100
}
```

Raw IDs work too:

```json
{
  "playlistInputs": ["PLBCF2DAC6FFB574DE"],
  "maxItems": 10
}
```

### Input parameters

#### `playlistInputs`

Required array of 1–50 strings.

Each value must be either:

- a public YouTube playlist URL containing a `list` query parameter; or
- a raw playlist ID containing at least 10 URL-safe characters.

Duplicate playlist IDs are processed once. Video watch URLs are accepted when they include a playlist `list` parameter.

#### `maxItems`

Optional integer from 1 to 10,000. Default: 100.

The limit applies globally across all unique playlists in input order. If the first playlist uses the entire allowance, later playlists are not requested.

### Output example

A current result has this shape:

```json
{
  "playlistInput": "PLBCF2DAC6FFB574DE",
  "playlistId": "PLBCF2DAC6FFB574DE",
  "playlistUrl": "https://www.youtube.com/playlist?list=PLBCF2DAC6FFB574DE",
  "playlistTitle": "Google Search Stories",
  "playlistDescription": "Searches can become stories.",
  "playlistOwnerName": "Google Search Stories",
  "playlistOwnerChannelId": "UCvceBgMIpKb4zK1ss-Sh90w",
  "playlistOwnerUrl": "https://www.youtube.com/@SearchStories",
  "playlistVisibility": "public",
  "playlistVideoCount": 13,
  "playlistViewCount": 102120,
  "playlistLastUpdatedText": "Last updated on Jun 17, 2014",
  "videoId": "GvgqDSnpRQM",
  "videoUrl": "https://www.youtube.com/watch?v=GvgqDSnpRQM",
  "title": "Andrew Willis, Skatepark Engineer",
  "position": 1,
  "channelName": "Google Search Stories",
  "channelId": "UCvceBgMIpKb4zK1ss-Sh90w",
  "channelUrl": "https://www.youtube.com/@SearchStories",
  "durationText": "1:30",
  "durationSeconds": 90,
  "publishedTimeText": "15 years ago",
  "viewCountText": "1.5M views",
  "viewCount": 1500000,
  "thumbnailUrl": "https://i.ytimg.com/vi/GvgqDSnpRQM/hqdefault.jpg",
  "thumbnails": [
    {
      "url": "https://i.ytimg.com/vi/GvgqDSnpRQM/hqdefault.jpg",
      "width": 336,
      "height": 188
    }
  ],
  "isPlayable": true,
  "retrievedAt": "2025-01-15T12:00:00.000Z"
}
```

Visible counts and relative publish text can change between runs. Treat `videoId`, `playlistId`, and `position` as the main snapshot-comparison keys.

### How much does it cost to extract YouTube playlist videos?

Pricing combines a **$0.001 one-time run start** with a tiered charge for each saved playlist video record.

The current BRONZE video price is **$0.0008 per video**. Higher subscription tiers receive lower per-video prices, which Apify applies automatically.

Example BRONZE totals:

| Saved videos | Start | Video events | Estimated total |
| ---: | ---: | ---: | ---: |
| 10 | $0.001 | $0.008 | $0.009 |
| 100 | $0.001 | $0.080 | $0.081 |
| 1,000 | $0.001 | $0.800 | $0.801 |

Failed, duplicate, filtered, or otherwise unsaved video rows do not emit the `video` event. Platform compute usage may still apply according to the user's Apify plan.

### Archive a playlist on a schedule

Use an Apify schedule with a stable input, then compare each new dataset with the prior run.

A practical comparison key is:

```text
playlistId + videoId + position
```

Typical change rules are:

- new `videoId`: video added;
- missing prior `videoId`: video removed or unavailable;
- same `videoId`, changed `position`: playlist reordered;
- changed title, view count, or publish text: visible metadata changed.

The Actor produces snapshots. It does not store history, send alerts, or calculate diffs inside the run; connect the dataset to your preferred database or automation tool for those actions.

### Export playlist videos to a spreadsheet

After a run, use the Dataset export menu to download CSV or Excel.

For recurring spreadsheet delivery, connect Apify with Make, Zapier, Google Sheets, or a webhook workflow. Recommended spreadsheet columns are:

- `playlistTitle`;
- `position`;
- `title`;
- `videoUrl`;
- `channelName`;
- `durationSeconds`;
- `publishedTimeText`;
- `viewCount`;
- `retrievedAt`.

### API usage with cURL

Start a run and wait for completion:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~youtube-playlist-videos-metadata-extractor/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "playlistInputs": ["PLBCF2DAC6FFB574DE"],
    "maxItems": 25
  }'
```

For production systems, keep the token in a secret manager rather than source code.

### API usage with JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

const run = await client
  .actor('automation-lab/youtube-playlist-videos-metadata-extractor')
  .call({
    playlistInputs: ['PLBCF2DAC6FFB574DE'],
    maxItems: 100,
  });

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.map(({ position, title, videoUrl }) => ({ position, title, videoUrl })));
```

### API usage with Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])

run = client.actor(
    "automation-lab/youtube-playlist-videos-metadata-extractor"
).call(run_input={
    "playlistInputs": ["PLBCF2DAC6FFB574DE"],
    "maxItems": 100,
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["position"], item["title"], item["videoUrl"])
```

### Use with Apify MCP

Add this Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/youtube-playlist-videos-metadata-extractor"
```

#### Claude Desktop MCP setup

Add this server to the Claude Desktop configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/youtube-playlist-videos-metadata-extractor"
    }
  }
}
```

#### Cursor MCP setup

Add the same `mcpServers.apify` entry in Cursor's MCP settings and restart the MCP client.

#### VS Code MCP setup

Add the same server URL to your VS Code MCP configuration, then enable the `apify` server for the workspace.

Example prompts:

- “Extract the first 50 videos from this public YouTube playlist and return titles, positions, and durations.”
- “Archive these three YouTube playlists and group the resulting records by playlist ID.”
- “Compare this dataset with yesterday's export and list added, removed, or reordered videos.”

The last prompt requires giving the MCP client access to both snapshots; the Actor itself returns only the current snapshot.

### Reliability and retry behavior

The Actor uses YouTube's logged-out structured web data rather than downloading watch pages or media.

Transient network failures, HTTP 429 responses, and temporary server errors are retried up to three times with bounded exponential backoff. Invalid input and stable client errors are not retried blindly.

Continuation tokens are deduplicated to prevent pagination loops. Video IDs are deduplicated within each playlist response while preserving the first observed position.

If several playlists are supplied, one inaccessible playlist is logged and later inputs continue. The run fails when none of the supplied playlists can be processed.

### Limitations

- Only playlists available to logged-out users are supported.
- Private, account-restricted, deleted, and some region- or age-restricted content may be absent or fail.
- Unavailable playlist rows are not guaranteed because YouTube may hide them from logged-out responses.
- Playlist and video fields reflect what YouTube exposes at retrieval time.
- Relative text such as “2 years ago” is not converted into an invented exact date.
- Displayed view counts can be rounded; normalized numeric counts therefore remain estimates of the displayed value.
- Playlist descriptions, owner URLs, counts, and update text can be `null` when not exposed.
- The Actor does not extract transcripts, tags, comments, audio, or media files.
- YouTube can change its undocumented public response structure.

### Responsible use and legality

Use this Actor only for public data you are authorized to collect and process.

You are responsible for complying with YouTube's terms, applicable laws, contractual obligations, privacy requirements, intellectual-property rights, and data-retention rules. Avoid collecting personal data without a lawful purpose. Do not use the output for spam, harassment, surveillance, or attempts to bypass access controls.

This Actor does not log in, bypass private-playlist permissions, or download copyrighted video content.

### Troubleshooting

#### “Invalid YouTube playlist input”

Check that each value is a playlist ID or a YouTube URL containing `list=...`. A plain video URL without a playlist parameter is not enough.

#### “No supplied playlist could be processed”

Open the playlist in a logged-out browser. It may be private, removed, empty, account-restricted, or temporarily unavailable. Review the run log for the playlist ID and upstream error.

#### Fewer rows than `maxItems`

`maxItems` is a ceiling, not a target. A playlist may contain fewer visible videos, duplicate entries, or unavailable rows that YouTube does not expose publicly.

#### Metadata fields are null

YouTube varies fields across regular videos, live streams, premieres, unavailable entries, and interface versions. Use stable IDs and URLs as primary keys and treat descriptive fields as nullable.

#### A scheduled run shows changed positions

That normally means the playlist owner reordered content. Compare `videoId` across snapshots before interpreting a moved position as a new or removed video.

### FAQ

#### Can I scrape more than one playlist?

Yes. Supply up to 50 URLs or IDs. The global `maxItems` cap is consumed in input order.

#### Does it support long playlists?

Yes. The Actor follows continuation pages until the playlist ends or `maxItems` is reached. The maximum output limit is 10,000 video records per run.

#### Does it need a YouTube Data API key?

No. The Actor retrieves public data visible to logged-out YouTube web clients.

#### Does it download videos or thumbnails?

No. It exports metadata and thumbnail URLs only.

#### Can it monitor additions and removals?

Yes as a snapshot source. Schedule recurring runs and compare dataset records downstream. The Actor does not retain history or send alerts itself.

#### Are playlist videos returned in order?

Yes. `position` is one-based and follows the playlist order returned by YouTube.

#### Can I request private playlists?

No. The Actor does not accept credentials and supports only publicly available playlists.

#### Why is the publish date relative text?

Playlist rows commonly expose relative text rather than an exact date. The Actor returns the source text instead of guessing an exact timestamp.

### Related Automation Lab Actors

- [YouTube Channel Videos Scraper](https://apify.com/automation-lab/youtube-channel-videos-scraper) — export recent public uploads from channels rather than playlist membership.
- [YouTube Video Tags Extractor](https://apify.com/automation-lab/youtube-video-tags-extractor) — retrieve creator-assigned tags for selected video IDs.
- [YouTube Transcript Scraper](https://apify.com/automation-lab/youtube-transcript) — extract available transcripts for downstream analysis.
- [YouTube Search Results Scraper](https://apify.com/automation-lab/youtube-search-results) — discover videos by keyword instead of a known playlist ID.

Choose this Actor when playlist identity, membership, and order are the core job.

# Actor input Schema

## `playlistInputs` (type: `array`):

Public YouTube playlist URLs or raw playlist IDs. Duplicate playlists are processed once.

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

Maximum number of ordered video records to save across all supplied playlists.

## Actor input object example

```json
{
  "playlistInputs": [
    "https://www.youtube.com/playlist?list=PLBCF2DAC6FFB574DE"
  ],
  "maxItems": 10
}
```

# Actor output Schema

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

Default dataset containing ordered public YouTube playlist video records.

# 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 = {
    "playlistInputs": [
        "https://www.youtube.com/playlist?list=PLBCF2DAC6FFB574DE"
    ],
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/youtube-playlist-videos-metadata-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 = {
    "playlistInputs": ["https://www.youtube.com/playlist?list=PLBCF2DAC6FFB574DE"],
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/youtube-playlist-videos-metadata-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 '{
  "playlistInputs": [
    "https://www.youtube.com/playlist?list=PLBCF2DAC6FFB574DE"
  ],
  "maxItems": 10
}' |
apify call automation-lab/youtube-playlist-videos-metadata-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/youtube-playlist-videos-metadata-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/vtsuFgfsoSAiEv0gR/builds/WMPqOs56Lq9Cw95gL/openapi.json
