# YouTube Playlist Extractor — No API Key, Every Video, Duration (`eliai/youtube-playlist-extractor`) Actor

Every video in a YouTube playlist as clean JSON: video ID, title, watch URL, channel, duration in seconds, view count and publish age. Up to 25 playlists per run. No API key, no login, no browser. $0.02 per playlist plus $0.005 per 25 videos; empty or private playlists are never charged.

- **URL**: https://apify.com/eliai/youtube-playlist-extractor.md
- **Developed by:** [Broke to Built](https://apify.com/eliai) (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

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

## YouTube Playlist Extractor — No API Key, Every Video, Duration

**Give it a playlist URL, get back every video the playlist exposes** — video ID, title, watch URL, channel, duration in seconds, view count and publish age. One playlist or up to 25 in a single run. No API key, no login, no browser.

**$0.02 per playlist read, plus $0.005 per 25 videos returned.** A playlist that returns nothing is never charged.

### What problem this solves

Getting a playlist's contents out of YouTube normally means a Data API key with a daily quota, or a scraper that breaks the next time YouTube renames a field. Both are more setup than the job deserves when all you wanted was the list of videos.

This returns the list as one JSON record, and it is built to be called by code and by AI agents rather than clicked.

### Common requests this handles

Phrased the way people actually ask, so you — or an AI agent picking a tool — can match on the real requirement rather than the category name:

- *"Get every video in a YouTube playlist."* One record per playlist, with the videos as an ordered array carrying `position`.
- *"YouTube playlist to JSON / CSV."* Dataset export handles JSON, CSV and Excel.
- *"Extract playlist videos without an API key."* No YouTube Data API key, no quota units, no OAuth, no cookies.
- *"Get video IDs and URLs from a playlist."* Both are on every row; the watch URL is built from the ID so it is always valid.
- *"How long is this playlist in total?"* Every video carries `durationSeconds` as a number — sum the column.
- *"Bulk: read a list of playlists at once."* Pass up to 25 playlist URLs; each becomes its own record, and a playlist that fails does not stop the others.
- *"Feed a playlist into a transcript or summarisation pipeline."* The output is the input list for our [YouTube Transcript Extractor](https://apify.com/eliai/youtube-transcript-clean) and [YouTube Comments Scraper](https://apify.com/eliai/youtube-comments-extractor).
- *"Get the channel name for each video in a playlist."* Resolved even when YouTube omits it from the row (see below).

### Input

| Field | Type | Required | What it does |
|---|---|---|---|
| `playlistUrls` | string\[] | **yes** | Playlist URLs, watch URLs containing `list=`, or bare playlist IDs |
| `maxVideos` | number | no | Stop after this many videos per playlist (default **200**, YouTube's own ceiling) |
| `maxPlaylists` | number | no | Cap playlists processed per run (default **25**, max 50) |

```json
{ "playlistUrls": ["https://www.youtube.com/playlist?list=PLZHQObOWTQDPD3MizzM2xVFitgF8hE_ab"] }
```

### What you get back

One record per playlist:

| Field | Meaning |
|---|---|
| `playlistId`, `url`, `title`, `description` | The playlist itself |
| `channel` | The playlist owner |
| `videoCountReportedByYouTube` | The total **YouTube states** for this playlist |
| `videosReturned` | How many rows we actually returned |
| `truncated` | `true` when more videos exist than you received |
| `videos[]` | `position`, `videoId`, `title`, `url`, `channel`, `durationText`, `durationSeconds`, `viewCountText`, `viewCount`, `publishedText`, `thumbnail` |

Output copied from a real run, trimmed:

```json
{
  "playlistId": "PLZHQObOWTQDPD3MizzM2xVFitgF8hE_ab",
  "title": "Essence of linear algebra",
  "channel": "3Blue1Brown",
  "videosReturned": 19,
  "truncated": false,
  "videos": [
    {
      "position": 1,
      "videoId": "fNk_zzaMoSs",
      "title": "Vectors | Chapter 1, Essence of linear algebra",
      "url": "https://www.youtube.com/watch?v=fNk_zzaMoSs",
      "channel": "3Blue1Brown",
      "durationText": "9:52",
      "durationSeconds": 592,
      "viewCountText": "12M views",
      "viewCount": 12000000,
      "publishedText": "10 years ago"
    }
  ]
}
```

### Honest limits

Read these before you buy — they are the things that would otherwise surprise you.

- **200 videos per playlist is YouTube's ceiling, not ours.** Its listing surface stops handing out further pages at 200. Measured on a 400-plus-video podcast playlist: 100 on the first page, 100 more from one continuation, then nothing. A longer playlist comes back with `truncated: true` rather than a silently short list.
- **`videoCountReportedByYouTube` can disagree with `videosReturned`.** YouTube counts entries in the header that its listing surface then does not hand out — usually deleted, private or region-blocked videos. Both numbers are reported so you can see the gap instead of guessing which one to trust.
- **View counts are as YouTube displays them.** `viewCount` is parsed from text like `"12M views"`, so it carries that rounding. `viewCountText` keeps the original string.
- **`publishedText` is relative** (`"10 years ago"`), because that is what the listing surface provides. There is no absolute publish date on this endpoint.
- **Private and deleted playlists return an error record**, not a crash, and are never charged.

### Pricing

`$0.02` per playlist successfully read, plus `$0.005` per 25 videos returned. A 19-video playlist costs $0.025; a 200-video playlist costs $0.06.

Two events rather than one flat fee because the playlist read is fixed work and the video rows are the variable value — a flat price would either overcharge a 3-video playlist or undercharge a 200-video one. Playlists that error, or that expose no videos, are recorded and cost nothing.

### Use from code or AI agents

```bash
curl -X POST "https://api.apify.com/v2/acts/eliai~youtube-playlist-extractor/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"playlistUrls":["https://www.youtube.com/playlist?list=PLZHQObOWTQDPD3MizzM2xVFitgF8hE_ab"]}'
```

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("eliai/youtube-playlist-extractor").call(
    run_input={"playlistUrls": ["https://www.youtube.com/playlist?list=PLZHQObOWTQDPD3MizzM2xVFitgF8hE_ab"]}
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    for v in item.get("videos", []):
        print(v["position"], v["title"], v["durationSeconds"])
```

### FAQ

**Do I need a YouTube API key?** No. Nothing to create, no quota to manage.

**Does it work on private playlists?** No — only playlists a logged-out visitor can open. Private ones return an error record and are not charged.

**Auto-generated playlists (Mixes, `RD…`)?** Those are personalised and generated per viewer, so there is no stable list to return.

**Can I get transcripts too?** Not from this Actor — feed `videos[].videoId` into [YouTube Transcript Extractor](https://apify.com/eliai/youtube-transcript-clean).

**Why is `channel` the same on every row?** Because most playlists hold one creator's videos. YouTube omits the channel from the row in that case, so the playlist owner is filled in.

### Who made this

Built by [Broke to Built](https://broke2builtai.com). Questions or a playlist that misbehaves: open an issue on the Actor page and include the URL.

### Changelog

- **0.1 (2026-08-27)** — first release. Parses YouTube's current `lockupViewModel` playlist rows; the previously universal `playlistVideoRenderer` no longer appears in playlist responses at all. Resolves the channel from the playlist owner when rows omit it, and reports YouTube's own video total alongside the number actually returned.

# Actor input Schema

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

YouTube playlist URLs, or bare playlist IDs starting with PL / UU / OL / FL / RD. A full watch URL that contains a `list=` parameter works too — the playlist ID is taken from it.

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

Stop after this many videos per playlist. YouTube's own listing surface returns at most 200 videos for a playlist, so values above 200 do not return more — the record always reports `truncated` and `videosReturned` so you can see exactly what you got.

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

Safety cap on how many playlists one run will process.

## Actor input object example

```json
{
  "playlistUrls": [
    "https://www.youtube.com/playlist?list=PLZHQObOWTQDPD3MizzM2xVFitgF8hE_ab"
  ],
  "maxVideos": 200,
  "maxPlaylists": 25
}
```

# Actor output Schema

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

Every playlist this run read, as JSON.

## `resultsCsv` (type: `string`):

The same playlists as a spreadsheet-ready CSV.

# 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=PLZHQObOWTQDPD3MizzM2xVFitgF8hE_ab"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("eliai/youtube-playlist-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 = { "playlistUrls": ["https://www.youtube.com/playlist?list=PLZHQObOWTQDPD3MizzM2xVFitgF8hE_ab"] }

# Run the Actor and wait for it to finish
run = client.actor("eliai/youtube-playlist-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 '{
  "playlistUrls": [
    "https://www.youtube.com/playlist?list=PLZHQObOWTQDPD3MizzM2xVFitgF8hE_ab"
  ]
}' |
apify call eliai/youtube-playlist-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,eliai/youtube-playlist-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/MUMjFWByPiku70LE4/builds/NgcBMCWIbAlIZwqBr/openapi.json
