# YouTube Playlist Contents & Channel Playlist Finder (`vexaloom-labs/youtube-playlist-contents-and-channel-playlist`) Actor

List every video in a YouTube playlist, or discover every public playlist a channel owns, with titles, durations, thumbnails, and playlist metadata.

- **URL**: https://apify.com/vexaloom-labs/youtube-playlist-contents-and-channel-playlist.md
- **Developed by:** [vexaloom-labs](https://apify.com/vexaloom-labs) (community)
- **Categories:** Videos, Social media, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.49 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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

## YouTube Playlist Contents & Channel Playlist Finder

Collect every video in a YouTube playlist, discover all of a channel's public collections, and search YouTube for playlists by keyword. Every available video can carry exact views, likes, publish date, description, category, and tags, while deleted or private entries can be returned as clearly marked placeholders with their real positions.

### What this actor does

- **Playlist contents** — every public video in one or many playlists, including 1,000+ item playlists
- **Hidden unavailable entries** — optional placeholder rows for deleted, private, or removed videos, preserving their true position
- **Exact video details** — views, likes, ISO publish date, description, category, tags, live status, and all thumbnail sizes
- **Channel collections** — playlists, shows, courses, podcasts, and albums with their real video/episode counts
- **Playlist search** — keyword search across public playlists and courses, ranked per query
- **Mixed runs** — combine playlist URLs, channel URLs, and search queries in one input
- **Empty fields are omitted** from every record

### Output: per video (`playlistUrls` mode)

- `recordType` — `video`
- `position` — the video's real position in the playlist, counting hidden entries
- `videoId`, `title`, `url`, `thumbnailUrl`, `thumbnails[]`
- `duration`, `durationSeconds`
- `isAvailable` — `false` for placeholder rows
- `viewCount`, `viewCountText` — exact views from the video page
- `likeCount` — exact likes when YouTube exposes them
- `publishedAt` — ISO 8601 date/time
- `publishedTimeText` — the relative label shown in the playlist
- `videoDescription`, `videoCategory`, `videoKeywords[]`, `isLiveContent`
- `videoChannelName`, `videoChannelId`, `videoChannelHandle`, `videoChannelUrl` — the video's uploader
- `playlistId`, `playlistTitle`, `playlistUrl`, `playlistType`
- `playlistVideoCount` — the count YouTube declares for the playlist
- `playlistAvailableVideoCount`, `playlistUnavailableVideoCount`
- `playlistTotalDurationSeconds`, `playlistTotalDuration`
- `playlistOwner`, `playlistOwnerChannelId`, `playlistOwnerHandle`, `playlistDescription`, `playlistViewCount`
- `playlistThumbnailUrl`, `playlistVisibility`
- `lastUpdated`, `lastUpdatedDate` — the latter only when the label contains an exact date
- `scrapedAt`

Placeholder rows keep `recordType`, `videoId`, `position`, `thumbnailUrl`, playlist context, and `isAvailable: false`. YouTube does not reveal the title or channel of a hidden entry, so those fields are omitted.

### Output: per playlist (`channelUrls` mode)

- `recordType` — `playlist`
- `playlistId`, `playlistUrl`, `title`, `playlistType` — `playlist`, `show`, `course`, `podcast`, `album`, `radio_mix`, or `uploads`
- `videoCount`, `videoCountText` — for example `28` and `"28 episodes"`
- `thumbnailUrl`
- `firstVideoId`, `firstVideoUrl` — where the collection starts
- `channelName`, `channelId`, `channelHandle`, `channelUrl`, `channelAvatarUrl`
- `lastUpdated` — when the card shows an update label
- `scrapedAt`

### Output: per search result (`searchQueries` mode)

- `recordType` — `playlist`
- `searchQuery`, `searchRank`
- `playlistId`, `playlistUrl`, `title`, `playlistType`
- `channelName`, `channelId`, `channelHandle`, `channelUrl`
- `thumbnailUrl`, `firstVideoId`, `firstVideoUrl`
- `scrapedAt`

Search cards do not show a reliable video count, so `videoCount` is omitted. Pass a returned playlist ID to `playlistUrls` to collect its contents.

### Output: status and error rows

If a playlist, channel, or query cannot be read, the dataset still receives a row with `recordType: "status"` or `"error"`, the relevant input, and a plain-language message, so an empty dataset never hides a failure.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `playlistUrls` | array | – | Playlist URLs, watch URLs with `list=`, or bare playlist IDs |
| `channelUrls` | array | – | Channel handles, URLs, or channel IDs whose collections you want |
| `searchQueries` | array | – | Playlist search terms, up to 20 per run |
| `maxPlaylists` | integer | `100` | Maximum collections to list per channel |
| `maxSearchResults` | integer | `20` | Maximum results per search query |
| `maxVideos` | integer | `0` | Maximum rows per playlist; `0` returns everything |
| `includeUnavailableVideos` | boolean | `false` | Emit placeholder rows for hidden playlist entries |
| `includeVideoDetails` | boolean | `true` | Add exact per-video metrics, dates, descriptions, categories, and tags |

Supported playlist formats include `youtube.com/playlist?list=...`, `youtube.com/watch?v=...&list=...`, `music.youtube.com/playlist?list=...`, `youtu.be/...?list=...`, and bare IDs such as `PL...`, `UU...`, `RD...`, or `OL...`.

#### Example: full playlist with exact video details

```json
{
    "playlistUrls": ["https://www.youtube.com/playlist?list=PL-osiE80TeTt2d9bfVyTiXJA-UTHn6WwU"],
    "maxVideos": 50,
    "includeVideoDetails": true
}
```

#### Example: recover hidden entries from a damaged playlist

```json
{
    "playlistUrls": ["PLhMDlPcDRBKQsawQMVty_dNztC8QgppML"],
    "includeUnavailableVideos": true,
    "includeVideoDetails": false
}
```

#### Example: discover every collection on a channel

```json
{
    "channelUrls": ["@kurzgesagt"],
    "maxPlaylists": 50
}
```

#### Example: search playlists and collect one result in the same run

```json
{
    "searchQueries": ["python course", "lofi study music"],
    "maxSearchResults": 10,
    "playlistUrls": ["PL-osiE80TeTt2d9bfVyTiXJA-UTHn6WwU"],
    "maxVideos": 20
}
```

### Use cases

- **Course catalogs** — export every lesson, its position, duration, and publish date from an educational playlist
- **Playlist backups** — snapshot a playlist's contents and see which entries have disappeared
- **Podcast and show indexing** — discover a channel's podcast, show, and course collections with episode counts
- **Content research** — search a topic, compare playlist titles and owners, then pull the winners' full contents
- **Channel audits** — inventory every public collection a creator has published
- **Viewership analysis** — compare exact views and likes across videos in the same playlist

### FAQ

**How many videos can one playlist return?**
YouTube allows up to 5,000 entries in a public playlist. The actor reads through the entire list and reports what the source actually exposes.

**Why is `playlistVideoCount` larger than the number of rows?**
The declared count includes entries YouTube hides from the normal list. Set `includeUnavailableVideos` to `true` to receive a placeholder for each hidden entry. `playlistAvailableVideoCount` and `playlistUnavailableVideoCount` show the split.

**Why do some exact fields appear on one video but not another?**
YouTube hides like counts on some videos and does not publish a category or tags for every upload. Those fields are omitted rather than estimated; the rest of the record stays intact. `publishedAt` contains a full timestamp when YouTube exposes one and a calendar date when only the date is available.

**Do I need a YouTube API key, login, or proxy?**
No. The actor reads public YouTube data with no account, key, cookie, or proxy setup.

**Why is `playlistViewCount` missing on some playlists?**
YouTube does not display an aggregate view count for every collection type, such as auto-generated radio mixes. When the source has no count, the field is omitted.

**Can I scrape private or personal playlists?**
No. Playlists such as Watch Later, Liked Videos, and other account-only lists are not publicly readable and are out of scope.

**Why do search results omit `videoCount`?**
Playlist search cards do not show a video count. The actor returns the result identity and ranking; use the returned playlist ID with `playlistUrls` to get the full contents and counts.

**What does `playlistOwner` contain?**
The owner's display name without the interface prefix, for example `Timeline - World History Documentaries` rather than `by Timeline - World History Documentaries`.

**Is this actor affiliated with YouTube?**
No. It is an independent tool that reads publicly visible YouTube pages and is not operated or endorsed by YouTube or Google.

# Actor input Schema

## `playlistUrls` (type: `array`):

YouTube playlist URLs, watch URLs with a list parameter, or bare playlist IDs whose videos you want. Combine with Channel URLs or Search Queries in one run.

## `channelUrls` (type: `array`):

Channel handles, URLs, or channel IDs. The actor lists every public playlist, show, course, podcast, and album on each channel.

## `searchQueries` (type: `array`):

Keywords to search for public playlists and courses, for example "python course" or "lofi study". Up to 20 queries per run.

## `maxPlaylists` (type: `integer`):

Maximum number of collections to list per channel.

## `maxSearchResults` (type: `integer`):

Maximum number of playlist results to return for each search query.

## `maxVideos` (type: `integer`):

Maximum number of rows to return per playlist. Set to 0 for every video. Unavailable placeholders count toward the limit when enabled.

## `includeUnavailableVideos` (type: `boolean`):

Emit a placeholder row for each deleted, private, or hidden playlist entry, with its real position and thumbnail.

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

Add exact views, likes, publish date, description, category, and tags for every available video. Turn off for a faster listing-only run.

## Actor input object example

```json
{
  "playlistUrls": [
    "https://www.youtube.com/playlist?list=PLgzTt0k8mXzEk586ze4BjvDXR7c-TUSnx"
  ],
  "maxPlaylists": 100,
  "maxSearchResults": 20,
  "maxVideos": 3,
  "includeUnavailableVideos": false,
  "includeVideoDetails": true
}
```

# Actor output Schema

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

Dataset containing playlist videos, channel collections, search results, and status rows.

# 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 = {
    "playlistUrls": [
        "https://www.youtube.com/playlist?list=PLgzTt0k8mXzEk586ze4BjvDXR7c-TUSnx"
    ],
    "maxVideos": 3,
    "includeUnavailableVideos": false,
    "includeVideoDetails": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("vexaloom-labs/youtube-playlist-contents-and-channel-playlist").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 = {
    "playlistUrls": ["https://www.youtube.com/playlist?list=PLgzTt0k8mXzEk586ze4BjvDXR7c-TUSnx"],
    "maxVideos": 3,
    "includeUnavailableVideos": False,
    "includeVideoDetails": True,
}

# Run the Actor and wait for it to finish
run = client.actor("vexaloom-labs/youtube-playlist-contents-and-channel-playlist").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 '{
  "playlistUrls": [
    "https://www.youtube.com/playlist?list=PLgzTt0k8mXzEk586ze4BjvDXR7c-TUSnx"
  ],
  "maxVideos": 3,
  "includeUnavailableVideos": false,
  "includeVideoDetails": true
}' |
apify call vexaloom-labs/youtube-playlist-contents-and-channel-playlist --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,vexaloom-labs/youtube-playlist-contents-and-channel-playlist"
        }
    }
}
```

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/Dg3fDelv93OSfgvkB/builds/swYZ3TQrDebcdec5a/openapi.json
