# YouTube Scraper: Channels, Shorts, Search & Video Details (`deepmine/youtube-scraper`) Actor

Scrape YouTube channel videos, Shorts, live streams, search results and playlists. Give channel links or @handles, search terms or video URLs; get a row per video: title, views, exact likes, comments, publish time, duration, description, tags, channel stats and subtitles at no extra cost. No login.

- **URL**: https://apify.com/deepmine/youtube-scraper.md
- **Developed by:** [DeepMine](https://apify.com/deepmine) (community)
- **Categories:** Videos, AI, Social media
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.19 / 1,000 videos

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?

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 Scraper: Channels, Shorts, Search & Video Details

Scrape **YouTube channel videos, Shorts and live streams, search results, playlists and single videos**: type a channel, a search term or a link and get one row per video with exact likes, exact publish time, duration, description, tags and the channel's About info.

| Type | Title | Channel | Views | Likes | Published (UTC) | Length |
|---|---|---|---|---|---|---|
| video | What's Left for Humans? | Esther Perel and Sal Khan | TED | 64,783 | 200 | 2026-10-06 15:00:08 | 00:20:47 |
| video | Am I going to jail for web scraping? | Fireship | 1,280,081 | 42,743 | 2024-07-26 16:47:34 | 00:04:34 |
| shorts | Is web scraping legal? 🫢😳 | Luke Barousse | 709,397 | 18,772 | 2022-11-20 18:38:21 | 00:00:44 |

<sub>Collected 2026-10-07 by the prefilled run below (3 of its 50 rows, shortened).</sub>

**$1.99 per 1,000 videos on Free, $1.49 on Starter, $1.29 on Scale and $1.19 on Business.** The prefilled run (50 videos: @TED 20 videos + 5 Shorts, and the search "web scraping" 20 videos + 5 Shorts) costs about **$0.07** on Starter. Nothing per run, nothing for videos your filters leave out, and **subtitles are included at no extra cost** when you turn them on.

Also in every row: the video's description and its links, hashtags, tags, category, comments count, and the channel's subscribers, description, links, country, join date, total videos and total views. No login, no YouTube API key, no browser.

### What you can scrape

| Input | Example | What you get |
|---|---|---|
| A channel | `https://www.youtube.com/@TED` or `@TED` | Its newest videos, Shorts and live streams (set how many of each) |
| One channel tab | `https://www.youtube.com/@TED/shorts` | Only that tab (Videos, Shorts or Live) |
| Search terms | `web scraping` | Videos, Shorts and/or live streams YouTube's search returns, with its filters (sort, upload date, length, HD, 4K, subtitles...) |
| A search link | `https://www.youtube.com/results?search_query=web+scraping` | The same as typing the words |
| A playlist | `https://www.youtube.com/playlist?list=PL...` | Its videos in playlist order |
| Videos and Shorts | `https://www.youtube.com/watch?v=...`, `https://youtu.be/...`, `https://www.youtube.com/shorts/...` | Full details of each |

### Ready-made examples

- [Scrape a YouTube channel's videos, views and likes (@MrBeast)](https://apify.com/deepmine/youtube-scraper/examples/youtube-channel-videos-scraper)
- [Scrape YouTube search results: the most viewed "AI agents" videos this month](https://apify.com/deepmine/youtube-scraper/examples/youtube-search-results-scraper)
- [Get the transcripts of a channel's latest videos (Y Combinator)](https://apify.com/deepmine/youtube-transcript-scraper/examples/youtube-channel-transcripts), with our YouTube Transcript API

Open one and press Try for free: it copies the input to your account, where you change the channel or the words.

### Use it from an AI agent or the API

Connect the Apify MCP server at `https://mcp.apify.com?tools=deepmine/youtube-scraper` (Claude, VS Code or any MCP client), or call the Actor through the Apify API. Give at least one of these:

| Key | For | Example |
|---|---|---|
| `startUrls` | Channels, @handles, channel tabs, playlists, search links, videos and Shorts | `[{"url": "https://www.youtube.com/@TED"}]` |
| `searchQueries` | YouTube search, one term per item | `["web scraping"]` |
| `channels` | Shorts only, by channel name | `["MrBeast"]` |

How many: `maxResults` (videos), `maxResultsShorts` and `maxResultStreams`, each per channel or search term; leave all three out for 50 videos. An input with none of the three keys above fails at once with a message saying so, and costs nothing. Subtitles: `"transcriptionAndSubtitle": "ALWAYS_SUBTITLES"` with `subtitlesLanguage` and `subtitlesFormat`.

### How fast is it?

Measured on the Apify platform on 2026-10-07 at the default 1,024 MB, same inputs as the most used YouTube scraper on the Store (it took 10.8 s to its first row and 18.9 s in total for the first input, 18.1 s and 35.3 s for the second):

| Input | First row | Whole run |
|---|---|---|
| @TED: 8 videos + 2 Shorts | 4.0-5.7 s | 5.3-8.1 s |
| Search "Crawlee": 10 videos | 4.3-6.8 s | 5.5-8.0 s |
| @TED: 300 videos | 5.3 s | 39 s |
| @TED: 60 videos with subtitles (SRT) | 4.3-6.7 s | 13-32 s |
| @mkbhd: 60 videos with subtitles (WebVTT, video's own language) | 6.7-7.8 s | 36-38 s |
| Search "recetas de cocina": 40 videos with Spanish subtitles (XML) | 5.5-6.7 s | 13-35 s |
| Search "python tutorial": 60 videos with subtitles, many of them 5-16 hours long | 6.8-18 s | 31-42 s |

Times are from pressing Start to the first row in the dataset, and to the end of the run. Subtitle runs vary most: every video needs one call that only some proxy IPs get through (a run finds 2-5 of them), so the same input took 12 s one time and 30 s another.

### How much does it cost?

You pay per video saved, nothing per run. Each video is charged once per run, even if two of your inputs list it.

| Apify plan | Price per 1,000 videos |
|---|---|
| Free | $1.99 |
| Starter | $1.49 |
| Scale | $1.29 |
| Business | $1.19 |

Videos that the "Published after" filter leaves out are not charged.

**Subtitles are included at no extra cost**: a video saved with its subtitles costs the same as one without, on every plan.

### Input

```json
{
  "startUrls": [{"url": "https://www.youtube.com/@TED"}],
  "searchQueries": ["web scraping"],
  "maxResults": 20,
  "maxResultsShorts": 5,
  "maxResultStreams": 0
}
```

- **YouTube links**: channels, @handles, channel tabs, playlists, search links, videos and Shorts.
- **Search terms**: one per line.
- **Max videos / Shorts / live streams**: per channel or search term. 0 = none of that kind. If you leave all three out, you get 50 videos; if you set only Shorts or live streams (an API call with just `maxResultsShorts`), you get only those, and no regular videos are charged.
- **Published after**: a date (2026-09-01) or a period (30 days). A channel tab sorted newest first stops at the first older video.
- **Channel: sort videos by**: Newest first (default), Most popular first or Oldest first, as the buttons above a channel's video list. One extra call per channel tab. With "Published after" on, a Popular or Oldest tab is read until 150 videos in a row are older than your date.
- **Subtitles (no extra cost)**: off by default. Turn on "Download subtitles", then pick the language (a code such as `en`, `es`, `pt-BR`, or `any` for the video's own language) and the format (SRT, WebVTT, XML as YouTube writes it, or plain text without times). A person-made track is taken before an automatic one. Videos in other languages than the one you pick are saved without subtitles.
- **Search filters**: sort by (relevance, upload date, views, rating), upload date (hour, today, week, month, year), length, and features (Live, 4K, HD, Subtitles/CC, Creative Commons, 360°, VR180, 3D, HDR, Location, Purchased).

Inputs written for `streamers/youtube-scraper` work as they are, every key of theirs is accepted: `startUrls`, `searchQueries`, `maxResults`, `maxResultsShorts`, `maxResultStreams`, `sortVideosBy`, `sortingOrder`, `dateFilter`, `videoType`, `lengthFilter`, the checkboxes `isHD`, `is4K`... `oldestPostDate`, and for subtitles `transcriptionAndSubtitle`, `subtitlesLanguage`, `subtitlesFormat`, `preferAutoGeneratedSubtitles`, `saveSubsToKVS`. Speech-to-text transcription and AI video descriptions or summaries are not offered: `TRANSCRIPTION_AS_FALLBACK` saves the videos' own subtitles only, `ALWAYS_TRANSCRIBE` saves no subtitles, `aiVideoDescription` and `aiVideoSummary` are ignored, and the run's status message says so.

### Output

One row per video (shortened):

```json
{
  "title": "Crawlee, the web scraping and browser automation library",
  "type": "video",
  "id": "g1Ll9OlFwEQ",
  "url": "https://www.youtube.com/watch?v=g1Ll9OlFwEQ",
  "thumbnailUrl": "https://i.ytimg.com/vi/g1Ll9OlFwEQ/maxresdefault.jpg",
  "viewCount": 13385,
  "likes": 167,
  "commentsCount": 15,
  "date": "2022-08-22T15:26:13Z",
  "duration": "00:03:14",
  "durationSeconds": 194,
  "text": "Crawlee helps you build reliable scrapers. Fast. ...",
  "descriptionLinks": [{"url": "https://crawlee.dev/", "text": "https://crawlee.dev/"}],
  "hashtags": ["#webscraping", "#crawlee"],
  "keywords": ["web scraping platform", "web automation", "scrapers", "Apify"],
  "category": "Science & Technology",
  "isAgeRestricted": false,
  "isMembersOnly": false,
  "commentsTurnedOff": false,
  "channelName": "Apify",
  "channelUrl": "https://www.youtube.com/channel/UCTgwcoeGGKmZ3zzCXN2qo_A",
  "channelUsername": "Apify",
  "numberOfSubscribers": 31300,
  "channelLocation": "Czechia",
  "channelJoinedDate": "Jan 4, 2017",
  "channelTotalVideos": 293,
  "channelTotalViews": 2325654,
  "channelDescriptionLinks": [{"text": "Browse tools", "url": "https://apify.com/store"}],
  "input": "Crawlee",
  "searchQuery": "Crawlee",
  "order": 0
}
```

With subtitles on, each row also has `subtitles` and `subtitlesStatus`:

```json
"subtitles": [{"type": "user_generated", "language": "en", "srt": "1\n00:00:00,000 --> 00:00:04,240\nWhat worries me is that we are more and\n\n2\n...", "srtUrl": null}],
"subtitlesStatus": "ok"
```

`type` is `user_generated` (a person made the track) or `auto_generated`; the text sits under the format's name (`srt`, `vtt`, `xml` or `plaintext`). `subtitlesStatus` says why a row has none: `noCaptions` (the video has no subtitles), `noMatchingLanguage` (none in your language), `emptyCaptions`, `captionFileFailed`, `tooLarge` (over 8 MB of text), `timeout` or `blocked` (YouTube refused every connection this run could use), or what YouTube says about the video (`private`, `ageRestricted`, `liveNotReady`...).

Also in every row: `dateText`, `location`, `isPaidContent`, `isUnlisted`, `isLiveNow`, `liveStartedAt`, `liveEndedAt`, `isChannelVerified`, `channelAvatarUrl`, `channelBannerUrl` (channel inputs), `channelDescription`, `collaborators` (videos made by several channels), `soundTitle`, `musicTitle` and `musicArtist` (Shorts: the sound, e.g. "Original Sound", and the song YouTube identified in it), `inputChannelUrl`, `fromYTUrl`, `fromChannelListPage` and `scrapedAt`. For rows to line up with `streamers/youtube-scraper` output, every row also has `aboutChannelInfo` (the channel fields above again, in one object) and the keys `translatedTitle`, `translatedText`, `transcriptionUrl`, `aiVideoDescription`, `aiVideoSummary` and `isMonetized`, which are always `null` here (no translation, AI text or speech-to-text); `subtitles` is `null` unless you turn subtitles on, and `srtUrl` is always `null` (the text is in the row).

The dataset has four views: **Videos**, **Video details**, **Channels** and **Subtitles**. Download as JSON, CSV, Excel or HTML, or read it through the Apify API.

### Good to know

- **Likes are exact** (1,414, not "1.4K"). Comment counts are exact on Shorts. Subscribers, and comment counts over 1,000 on other videos, are as YouTube shows them (27.9M, 13K).
- **The publish time is exact** (to the second, UTC). It comes from a proxy IP that passes YouTube's bot check, from the channel's feed, or, for the few rows neither covers in time, from one small call through residential proxy (at our cost, not yours). 300 of 300 rows had it in four test runs (two channels of 60 videos, TED 100 videos + 20 Shorts, a search of 60).
- **Subtitles reach almost every video that has them.** In nine test runs at the default memory, 466 of the 468 videos with subtitles in the chosen language had them in their row; the other two timed out. Of the videos without, 5 had no subtitles at all and 22 had other languages only.
- The run log's `OUTPUT` record lists every input with how many videos it found and why one failed, if one did.

### FAQ

**Do I need a YouTube account or API key?** No. The Actor reads what YouTube shows anyone who isn't logged in.

**Can I scrape a whole channel?** Yes: set Max videos to the number you want (up to 10,000 per channel tab).

**Does it get comments or transcripts?** Subtitles, yes, at no extra cost. Comments: use our [YouTube Comments Scraper](https://apify.com/deepmine/youtube-comments-scraper). For transcripts in many languages and translations, use our [YouTube Transcript API](https://apify.com/deepmine/youtube-transcript-scraper).

**Can I sort a channel by most popular?** Yes: "Channel: sort videos by" = Most popular first (or Oldest first).

**Are long videos a problem for subtitles?** No: a 16-hour stream's subtitles take a minute or two, and the row waits for them. A row waits up to 20 seconds plus one second per ten minutes of video (at most two minutes); after that it is saved without subtitles.

### Did it help?

A short review on the Actor's page helps other people find it and tells us what to improve: https://apify.com/deepmine/youtube-scraper/reviews. Something missing or wrong? Write to us through the Actor's Issues tab.

# Actor input Schema

## `startUrls` (type: `array`):

Channel links or @handles (e.g. https://www.youtube.com/@TED or @TED), video and Shorts links, playlists or search result links. A channel link reads its Videos, Shorts and Live tabs up to maxResults, maxResultsShorts and maxResultStreams; a link ending in /shorts or /streams reads that tab only. Give at least one of startUrls, searchQueries or channels.

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

Words you'd type in YouTube's search box, one per line, e.g. web scraping. Each term returns up to maxResults videos (plus maxResultsShorts Shorts and maxResultStreams live streams).

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

Regular videos per channel, playlist or search term. 0 = none. Left out: 50, unless you set only Shorts or live streams (then no regular videos).

## `maxResultsShorts` (type: `integer`):

Shorts per channel (its Shorts tab) or search term. 0 = none.

## `maxResultStreams` (type: `integer`):

Live and past live streams per channel (its Live tab) or search term. 0 = none.

## `oldestPostDate` (type: `string`):

Keep only videos published on or after this date, e.g. 2026-09-01 or 30 days. Channel tabs stop at the first older video. Empty = any date.

## `sortVideosBy` (type: `string`):

Order of a channel's videos, Shorts and live streams (the tab's Latest / Popular / Oldest). Empty = newest first.

## `sortingOrder` (type: `string`):

Order of search results. Empty = YouTube's relevance.

## `dateFilter` (type: `string`):

Only search results uploaded in this period. Empty = any time.

## `lengthFilter` (type: `string`):

Only search results of this length. Empty = any length.

## `videoType` (type: `string`):

Search for videos or for movies. Empty = videos.

## `searchFeatures` (type: `array`):

Only search results with all of these, e.g. HD and Subtitles/CC. Empty = no feature filter.

## `channels` (type: `array`):

Shorts only: channel names without the @ (e.g. MrBeast) or channel links. Reads each channel's Shorts tab, up to maxResultsShorts (1 when that is 0). For a channel's regular videos, put its link or @handle in startUrls instead. Accepted so saved inputs from other YouTube Shorts scrapers run.

## `sortChannelShortsBy` (type: `string`):

NEWEST, POPULAR or OLDEST: order of the Shorts read for channels (the Shorts tab's Latest / Popular / Oldest). Empty = the sortVideosBy order.

## `transcriptionAndSubtitle` (type: `string`):

Download each video's own subtitles into the subtitles column. Speech-to-text transcription is not offered: saved inputs that ask for it still run, with a note in the run's status message.

## `subtitlesLanguage` (type: `string`):

A language code such as en, de, es, pt-BR or ja, or any for the video's own language. Only used when subtitles are on.

## `subtitlesFormat` (type: `string`):

How the subtitles are written. Plain text has no times.

## `preferAutoGeneratedSubtitles` (type: `boolean`):

Take YouTube's automatic subtitles before a person-made track.

## `proxyConfiguration` (type: `object`):

Leave as is: Apify datacenter proxy works for every YouTube call this Actor makes.

## `isHD` (type: `boolean`):

true = only search results with this feature, the same as adding isHD to searchFeatures. Accepted so saved inputs from other YouTube scrapers run.

## `hasSubtitles` (type: `boolean`):

true = only search results with this feature, the same as adding hasSubtitles to searchFeatures. Accepted so saved inputs from other YouTube scrapers run.

## `hasCC` (type: `boolean`):

true = only search results with this feature, the same as adding hasCC to searchFeatures. Accepted so saved inputs from other YouTube scrapers run.

## `is3D` (type: `boolean`):

true = only search results with this feature, the same as adding is3D to searchFeatures. Accepted so saved inputs from other YouTube scrapers run.

## `isLive` (type: `boolean`):

true = only search results with this feature, the same as adding isLive to searchFeatures. Accepted so saved inputs from other YouTube scrapers run.

## `isBought` (type: `boolean`):

true = only search results with this feature, the same as adding isBought to searchFeatures. Accepted so saved inputs from other YouTube scrapers run.

## `is4K` (type: `boolean`):

true = only search results with this feature, the same as adding is4K to searchFeatures. Accepted so saved inputs from other YouTube scrapers run.

## `is360` (type: `boolean`):

true = only search results with this feature, the same as adding is360 to searchFeatures. Accepted so saved inputs from other YouTube scrapers run.

## `hasLocation` (type: `boolean`):

true = only search results with this feature, the same as adding hasLocation to searchFeatures. Accepted so saved inputs from other YouTube scrapers run.

## `isHDR` (type: `boolean`):

true = only search results with this feature, the same as adding isHDR to searchFeatures. Accepted so saved inputs from other YouTube scrapers run.

## `isVR180` (type: `boolean`):

true = only search results with this feature, the same as adding isVR180 to searchFeatures. Accepted so saved inputs from other YouTube scrapers run.

## `aiVideoDescription` (type: `boolean`):

Accepted so saved inputs from other YouTube scrapers run: not offered, ignored (AI text columns are not written; subtitles are always in the row).

## `aiVideoSummary` (type: `boolean`):

Accepted so saved inputs from other YouTube scrapers run: not offered, ignored (AI text columns are not written; subtitles are always in the row).

## `saveSubsToKVS` (type: `boolean`):

Accepted so saved inputs from other YouTube scrapers run: not offered, ignored (AI text columns are not written; subtitles are always in the row).

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.youtube.com/@TED"
    }
  ],
  "searchQueries": [
    "web scraping"
  ],
  "maxResults": 20,
  "maxResultsShorts": 5,
  "maxResultStreams": 0,
  "transcriptionAndSubtitle": "NONE",
  "subtitlesLanguage": "en",
  "subtitlesFormat": "srt",
  "preferAutoGeneratedSubtitles": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

No description

## `summary` (type: `string`):

No description

# 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 = {
    "startUrls": [
        {
            "url": "https://www.youtube.com/@TED"
        }
    ],
    "searchQueries": [
        "web scraping"
    ],
    "maxResults": 20,
    "maxResultsShorts": 5,
    "maxResultStreams": 0
};

// Run the Actor and wait for it to finish
const run = await client.actor("deepmine/youtube-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 = {
    "startUrls": [{ "url": "https://www.youtube.com/@TED" }],
    "searchQueries": ["web scraping"],
    "maxResults": 20,
    "maxResultsShorts": 5,
    "maxResultStreams": 0,
}

# Run the Actor and wait for it to finish
run = client.actor("deepmine/youtube-scraper").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 '{
  "startUrls": [
    {
      "url": "https://www.youtube.com/@TED"
    }
  ],
  "searchQueries": [
    "web scraping"
  ],
  "maxResults": 20,
  "maxResultsShorts": 5,
  "maxResultStreams": 0
}' |
apify call deepmine/youtube-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,deepmine/youtube-scraper"
        }
    }
}
```

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/5VwXmeTWZgeo0fxXf/builds/kV7t08Y53KiS38beR/openapi.json
