# YouTube Scraper - Videos, Channels, Comments & Subtitles (`alom/youtube-scraper`) Actor

YouTube API alternative with no quota or key: channels, videos, Shorts, live streams, playlists, search, hashtags, community posts, comments and replies, subtitles (SRT/VTT/text), chapters and exact upload dates. Drop-in input for popular YouTube scrapers. From $0.80 per 1,000.

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

## Pricing

from $0.80 / 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/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

Scrape **YouTube** into JSON, CSV or Excel: **channel videos, Shorts, live streams, community posts and playlists,
hashtag pages, search results (videos, Shorts, channels, playlists), video details, subtitles and comments (with
replies)**. You get titles, views, likes, comment counts, exact upload times, durations, descriptions and their links,
chapters, hashtags, tags, related videos, channel subscribers, location and join date, and full comment threads.

✅ **No login, no API key, no quota:** it reads the same data youtube.com shows logged-out visitors.
✅ **One Actor for channels, Shorts, streams, posts, playlists, hashtags, search, subtitles and comments.**
✅ **YouTube transcripts from captions:** a video's subtitles (manual or auto-generated) as plain text, SRT or VTT, in every language the video has captions for.
✅ **Drop-in compatible** with the most-used YouTube scrapers' input and output field names.
✅ **Monitoring mode:** return only videos and comments you haven't seen yet, on a schedule.
✅ **You never pay for errors:** a deleted video or an unknown channel produces no row and no charge.

### What can you use YouTube data for?

- **Influencer & creator research:** subscribers, upload frequency, views and likes per video, country.
- **Competitor and brand monitoring:** new videos from a list of channels every day, and what viewers say about them.
- **Content & trend research:** what ranks for a keyword this week, which Shorts take off, which formats get likes.
- **Audience research / sentiment analysis:** thousands of comments and replies per video.
- **AI & research datasets:** titles, descriptions, tags and comments at scale.

### Switching from another YouTube scraper?

1. **Keep your input.** These fields work the same way as in the most-used YouTube scrapers:
   `startUrls`, `searchQueries`, `maxResults`, `maxResultsShorts`, `maxResultStreams`, `sortingOrder`, `dateFilter`,
   `videoType`, `lengthFilter`, `isHD`/`is4K`/`isLive`/… filters, `oldestPostDate`, `sortVideosBy`, `channels`,
   `sortChannelShortsBy`, `maxComments`, `sortCommentsBy`, `oldestCommentDate`, and the subtitle options
   `transcriptionAndSubtitle`, `subtitlesLanguage`, `subtitlesFormat`, `preferAutoGeneratedSubtitles`, `saveSubsToKVS`.
   Also understood: `keywords`, `youtubeHandles`, `maxItems`, `uploadDate`, `duration`, `features`, `sort`, `gl`,
   `includeShorts` (apidojo-style input).
2. **Change the Actor ID** to this one.
3. **Your pipeline keeps working:** rows use the same field names - `id`, `title`, `url`, `viewCount`, `likes`,
   `commentsCount`, `date`, `duration`, `text`, `hashtags`, `channelName`, `channelUrl`, `channelId`,
   `channelUsername`, `numberOfSubscribers`, `channelTotalVideos`, `channelTotalViews`, `channelJoinedDate`,
   `channelLocation`, `fromYTUrl`, `fromChannelListPage`, `descriptionLinks`, `subtitles`, `isMembersOnly`,
   `isAgeRestricted`, `order`, `type` (`video` / `shorts`); comments use `cid`, `comment`, `author`, `videoId`,
   `pageUrl`, `title`, `voteCount`, `replyCount`, `replyToCid`, `authorIsChannelOwner`, `hasCreatorHeart`.

Differences worth knowing:

- Coming from a **comments-only** scraper? Add `"commentsOnly": true`, otherwise you also get one row per video.
- `date` is always an ISO timestamp. Where YouTube only says "3 weeks ago" it is an estimate and `dateIsExact` is
  `false`; the original text is in `dateText`. `duration` is `HH:MM:SS`, plus `durationSeconds`.
- Subtitles: the ones YouTube has (uploaded or automatic). No AI speech-to-text transcription.
- Errors (deleted video, unknown channel, a URL that is not YouTube) are **not** written as dataset rows, so you are
  never charged for them. They are named in the run's status message, the `NOT_FOUND` key-value record and the log.
  One bad URL never stops the rest of the run.

### What you can scrape

| Input | Example | Output |
|---|---|---|
| Channel | `https://www.youtube.com/@MrBeast`, `/channel/UC…`, `/c/…`, `/user/…` | its videos (`maxResults`), Shorts (`maxResultsShorts`), streams (`maxResultStreams`), each with channel info |
| Channel tab | `…/@MrBeast/shorts`, `…/@NASA/streams`, `…/@MrBeast/posts`, `…/@kurzgesagt/playlists` | only that tab |
| Community posts | a channel + `maxPosts` (or a `/posts` URL) | `post` rows: text, images, poll, attached video, **exact likes**, comment count, date |
| Channel playlists | a channel + `maxPlaylists` (or a `/playlists` URL) | `playlist` rows: title, URL, number of videos |
| Channel info | any channel with all limits set to `0` | one `channel` row: subscribers, videos, total views, country, joined, links |
| Search | `searchQueries: ["lofi hip hop"]` or a `/results?search_query=…` URL | videos, with upload date / length / type / feature filters; **Type = Shorts, Channels or Playlists** returns those |
| Hashtag | `https://www.youtube.com/hashtag/cats` or `hashtags: ["cats"]` | videos (and Shorts with `maxResultsShorts`) |
| Playlist | `https://www.youtube.com/playlist?list=…` | its videos in playlist order |
| Video or Short | `https://www.youtube.com/watch?v=…`, `youtu.be/…`, `/shorts/…` | full details: exact views, likes, comment count, exact upload time, duration, tags, category, chapters, description links |
| Subtitles | any videos + `downloadSubtitles` | SRT / WebVTT / XML / plain text in the chosen language |
| Related videos | any videos + `includeRelatedVideos` | the ~20 "Up next" videos per video |
| Comments | any of the above + `maxComments` | comments (Top or Newest), optionally replies |

### Output examples

A video (from a channel, with `includeVideoDetails`):

```json
{
    "type": "video",
    "id": "v9QtM6qnG50",
    "url": "https://www.youtube.com/watch?v=v9QtM6qnG50",
    "title": "I Built A City To Save Kids From Illegal Labor",
    "text": "Huge thanks to the 1 Billion Followers Summit, …",
    "viewCount": 82636809,
    "viewCountText": "82,636,809 views",
    "likes": 2032918,
    "commentsCount": 94000,
    "commentsTurnedOff": false,
    "date": "2026-09-19T16:00:01.000Z",
    "dateText": "10 days ago",
    "dateIsExact": true,
    "duration": "00:19:02",
    "durationSeconds": 1142,
    "thumbnailUrl": "https://i.ytimg.com/vi/v9QtM6qnG50/hq720_custom_2.jpg?…",
    "hashtags": [],
    "keywords": [],
    "category": "Entertainment",
    "descriptionLinks": [{ "url": "https://www.1billionsummit.com/", "text": "https://www.1billionsummit.com/" }],
    "chapters": [{ "title": "Intro", "startSeconds": 0, "timeText": "0:00" }],
    "chaptersAutoGenerated": false,
    "isMembersOnly": false,
    "isAgeRestricted": false,
    "isUnlisted": false,
    "liveStatus": null,
    "channelId": "UCX6OQ3DkcsbYNE6H8uQQuVA",
    "channelName": "MrBeast",
    "channelUrl": "https://www.youtube.com/channel/UCX6OQ3DkcsbYNE6H8uQQuVA",
    "channelUsername": "MrBeast",
    "numberOfSubscribers": 519000000,
    "isChannelVerified": true,
    "channelLocation": "United States",
    "channelJoinedDate": "Feb 19, 2012",
    "channelTotalVideos": 1004,
    "channelTotalViews": 141227305543,
    "detailsScraped": true,
    "subtitles": null,
    "subtitleLanguages": null,
    "relatedVideos": null,
    "fromChannelListPage": "videos",
    "order": 0,
    "fromYTUrl": "https://www.youtube.com/@MrBeast/videos",
    "input": "https://www.youtube.com/@MrBeast",
    "scrapedAt": "2026-09-30T11:40:00.000Z"
}
```

A comment:

```json
{
    "type": "comment",
    "cid": "Ugzge340dBgB75hWBm54AaABAg",
    "comment": "can confirm: he never gave us up",
    "author": "@YouTube",
    "authorChannelId": "UCBR8-60-B28hp2BmDPdntcQ",
    "authorIsChannelOwner": false,
    "authorIsVerified": true,
    "hasCreatorHeart": true,
    "isPinned": true,
    "voteCount": 321000,
    "replyCount": 963,
    "date": "2025-09-30T11:38:17.654Z",
    "publishedTimeText": "1 year ago",
    "isReply": false,
    "replyToCid": null,
    "videoId": "dQw4w9WgXcQ",
    "pageUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "title": "Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)",
    "commentsCount": 2457929
}
```

A community post:

```json
{
    "type": "post",
    "postId": "UgkxHIfkQ3K2my65-kPq4VkRv9KrBRyN7alx",
    "url": "https://www.youtube.com/post/UgkxHIfkQ3K2my65-kPq4VkRv9KrBRyN7alx",
    "text": "NO MORE WAITING, this Saturday …",
    "date": "2026-09-29T13:58:34.465Z",
    "dateText": "1 day ago",
    "likes": 147168,
    "commentsCount": 3600,
    "attachmentType": "image",
    "images": ["https://yt3.ggpht.com/…"],
    "videoId": null,
    "poll": null,
    "isMembersOnly": false,
    "channelId": "UCX6OQ3DkcsbYNE6H8uQQuVA",
    "channelName": "MrBeast",
    "channelUsername": "MrBeast",
    "fromYTUrl": "https://www.youtube.com/@MrBeast/posts"
}
```

Shorts rows have `"type": "shorts"` and a `/shorts/` URL; streams have `"type": "stream"` and `liveStatus`
(`live`, `upcoming`, `was_live`). Values YouTube doesn't show on a given page are `null`, never a made-up `0`.

### How much does it cost?

**Proposed pricing** (not live yet): pay per result, platform usage (compute and proxy) included.
One result = one video, Short, stream, comment or channel row.

| Apify plan | Price per 1,000 results |
|---|---|
| Free | $1.50 |
| Starter (Bronze) | $1.25 |
| Scale (Silver) | $1.00 |
| Business (Gold) and above | $0.80 |

- 1,000 videos from 10 channels: **$1.50** on the Free plan, **$0.80** on Business.
- 10,000 comments: **$15** on Free, **$8** on Business - the popular comments scraper charges $9-20.
- **Full video details and comments cost the same per row** - they only make the run take longer (see below).

### Full video details (`includeVideoDetails`)

Channel, search and playlist pages show YouTube's rounded numbers ("82M views", "3 weeks ago") and no likes. With
**Add full video details** on, the scraper opens every video (2 extra requests) and adds exact views, likes,
comment count, the exact upload time, duration, full description and its links, chapters, tags (`keywords`),
category and the members-only / age-restricted flags. This makes runs roughly 5-10x slower (measured: 300 videos in
about 4 minutes) but does not change the price per row. Video URLs you enter directly always get full details.

### Subtitles (`downloadSubtitles`)

Turn on **Download subtitles** and pick a language (`en`, `de`, `pt-BR`, … or `any`) and a format (`srt`, `vtt`,
`xml`, `plaintext`). Each video row gets `subtitles: [{ language, languageName, type, format, srt }]` (`type` is
`user_generated` or `auto_generated`) and `subtitleLanguages` - every language the video has. A video without
subtitles in that language gets `subtitles: []`; if YouTube does not show the list (age-restricted or members-only
videos) it is `null`. **Also save subtitles as files** puts each file in the run's key-value store (`srtUrl`).
There is no AI transcription and no machine translation. The price per row stays the same.

### Your own cookies (optional, advanced)

Everything above works without an account. The only thing YouTube hides from logged-out visitors is
**age-restricted videos** (exact data, subtitles) **and their comments**. For those, you can paste the cookies of a
logged-in youtube.com browser tab into **Your YouTube cookies** (a cookie-extension JSON export, a cookies.txt file or
a `name=value; …` header).

> ⚠️ **Use a secondary Google account, never your main one.** Requests are then made as that account from many
> proxy IPs; YouTube may ask it to verify itself or restrict it for automated use. The field is stored encrypted and
> the cookies are never logged or written to the dataset. We could not test this mode against a real account - if
> something looks off, tell us on the Issues tab.

### Monitoring (only new videos / comments)

Turn on **"Only new videos/comments since my last run"**, give it a name (e.g. `competitors-daily`) and schedule the
run. Each run looks at the newest `maxResults` videos of each channel (and `maxComments` comments of each video) and
returns only the ones no earlier run with that name returned. Videos you entered as URLs are returned once; their
new comments every run.

```json
{ "channels": ["mkbhd", "veritasium"], "maxResults": 20, "maxComments": 50, "sortCommentsBy": "NEWEST_FIRST", "deltaMode": true, "monitorName": "tech-daily" }
```

### Limitations

- **No AI transcripts, summaries or subtitle translation** - only the subtitles YouTube has. Getting the subtitle
  list needs YouTube's app API, which bot-checks about 2 in 3 datacenter IPs: the scraper rotates IPs and, if you
  kept the default proxy, tries once on a residential IP (logged, counted in `STATISTICS`). A video it still cannot
  get has `subtitles: null` and the run says "partial".
- **Sorting search results by upload date or rating** is no longer honoured by YouTube itself (results come back
  by relevance). Use the **Upload date** filter (`dateFilter`) for recent videos; **View count** sorting works.
- **Shorts tiles have no date or duration.** With `oldestPostDate` the scraper checks each Short's exact date
  automatically; for dates on every Short turn on `includeVideoDetails`.
- **Comment dates are approximate** ("3 days ago" is all YouTube shows) and comment like counts are rounded
  ("321K"). The video's total comment count is exact.
- **Search returns at most ~500-700 videos per query** (YouTube stops paging). Use several queries or filters for more.
- **Exact upload time and duration** come from YouTube's player data, which YouTube sometimes withholds from a proxy
  IP ("confirm you're not a bot"). The scraper asks the YouTube Music player first (rarely checked), then the web
  player, on new IPs; if both fail, the row keeps the day-precise date, views and likes (`dateIsExact` stays `true`
  for the day).
- **Hashtag pages** show logged-out visitors only ~20-30 videos. Beyond that, the scraper tops up from a search for
  the hashtag (those rows have the search URL in `fromYTUrl`).
- **Members-only and private videos:** flagged (`isMembersOnly`) with what YouTube shows publicly; their content and
  comments need a paying member's login. **Trending** no longer exists on YouTube (removed in 2025).
- Not available logged out: dislikes, `isMonetized`, video download links.

### FAQ

**Do I need a YouTube account or an API key?** No. Nothing to configure, and no YouTube API quota.

**Is it legal?** It collects publicly visible data. You are responsible for how you use it, including data
protection rules for personal data (usernames, comments).

**Why did my run say "partial"?** Some inputs could not be finished (e.g. the run hit its timeout, or YouTube kept
refusing one request). Everything that was scraped is in the dataset; the status message says what was missed.

### More scrapers from the same developer

- [Google Trends API & Scraper](https://apify.com/alom/google-trends-scraper): interest over time, regions, related queries and Trending Now, a pytrends alternative
- [Threads Scraper](https://apify.com/alom/threads-scraper): posts, profiles, replies and keyword search on Meta Threads, no login
- [Bilibili Scraper](https://apify.com/alom/bilibili-scraper): videos, creators, full comment threads and danmaku from B站, no login
- [Google Hotels Scraper](https://apify.com/alom/google-hotels-scraper): hotel prices from every booking site across dates, room rates and reviews
- [Google Ads Transparency Scraper](https://apify.com/alom/google-ads-transparency-scraper): every Google ad a competitor runs, with the real ad copy
- [Threads Account Finder](https://apify.com/alom/threads-lead-finder): Threads accounts by keyword with followers, bio links and the contacts they list
- [Threads Hashtag & Keyword Monitor](https://apify.com/alom/threads-keyword-monitor): only the new posts for your keywords and #hashtags, for scheduled runs

### Feedback

Missing a field, found a bug, or need a feature? Open an issue in the **Issues** tab and I'll take a look. If this
Actor saved you time, a short review on the Store page helps other people find it.

# Actor input Schema

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

Any mix of <b>channel</b> (<code>/@handle</code>, <code>/channel/UC…</code>, <code>/c/…</code>, <code>/user/…</code>, also a single tab: <code>/@handle/shorts</code>, <code>/streams</code>, <code>/posts</code> (community), <code>/playlists</code>), <b>video</b> or <b>Shorts</b> URLs, <b>playlists</b>, <b>hashtag pages</b> (<code>/hashtag/…</code>) and <b>search result pages</b> (<code>/results?search\_query=…</code>). A URL that is not YouTube is skipped and reported; it does not stop the run.

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

Keywords, exactly as you would type them into YouTube's search bar. Each keyword returns up to <b>Max videos</b> results.

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

Optional: channel handles without the @ (e.g. <code>nasa</code>) or channel URLs. Same as putting the channel URL in <b>YouTube URLs</b>.

## `hashtags` (type: `array`):

Optional: hashtags with or without <code>#</code> (e.g. <code>cats</code>). YouTube shows logged-out visitors only ~20-30 videos on a hashtag page; the rest up to <b>Max videos</b> comes from a search for the hashtag (those rows have a search URL in <code>fromYTUrl</code>). Shorts: set <b>Max Shorts</b>.

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

Regular videos per channel, per search term and per playlist. Set to 0 (and the two fields below to 0) to get one <b>channel info</b> row per channel.

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

Shorts from each channel's Shorts tab.

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

Past, live and upcoming streams from each channel's Live tab.

## `maxPosts` (type: `integer`):

Posts from each channel's <b>Posts</b> (community) tab: text, images, polls, exact like count, comment count. Respects <b>Only videos published after</b>.

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

One row per playlist on each channel's <b>Playlists</b> tab (title, URL, number of videos). To get a playlist's videos, add its URL to <b>YouTube URLs</b>.

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

Opens every video from a channel, search or playlist to add <b>exact</b> views, <b>likes</b>, comment count, exact upload time, duration, full description, tags and category. About 2 extra requests per video, so runs take longer - the price per result stays the same. Video URLs you enter always get full details.

## `includeRelatedVideos` (type: `boolean`):

Adds the ~20 videos YouTube suggests next to each video (<code>relatedVideos</code>: id, title, channel, views, duration). Needs one extra request per video from channels, searches and playlists; free for video URLs.

## `downloadSubtitles` (type: `boolean`):

Adds the video's subtitles (uploaded or YouTube's automatic ones) in the language and format below, plus the list of languages available (<code>subtitleLanguages</code>). No AI transcription: videos without subtitles get <code>subtitles: \[]</code>. Costs no extra per row; about 2 extra requests per video.

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

Language code (<code>en</code>, <code>de</code>, <code>pt-BR</code>, …) or <code>any</code> for the video's first track. <code>en</code> also matches <code>en-GB</code> etc.

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

The text is in the field named after the format (<code>srt</code>, <code>vtt</code>, …).

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

Use YouTube's automatic (speech-recognition) subtitles even when the uploader provided some.

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

Saves each subtitle file to the run's key-value store; its link is in <code>srtUrl</code> (or <code>vttUrl</code>, …).

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

YouTube currently honours only <b>Relevance</b> and <b>View count</b> / <b>Popularity</b> (the same sort); for recent videos use <b>Upload date</b> below.

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

Search only.

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

Search only. <b>Channels</b> returns one channel row per result (name, handle, subscribers); <b>Playlists</b> one playlist row per result.

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

Search only.

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

Search only: HD videos.

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

Search only: Subtitles/CC videos.

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

Search only: Creative Commons videos.

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

Search only: 3D videos.

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

Search only: Live videos.

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

Search only: Purchased videos.

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

Search only: 4K videos.

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

Search only: 360° videos.

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

Search only: Location videos.

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

Search only: HDR videos.

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

Search only: VR180 videos.

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

A date (<code>2026-01-31</code>) or an age (<code>30 days</code>, <code>2 weeks</code>, <code>6 months</code>). <code>1 day</code> = today only. Applies to channel Videos, Shorts and Live tabs and forces <b>Newest</b> order.

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

The sort buttons on a channel's Videos, Shorts and Live tabs.

## `maxComments` (type: `integer`):

Comments for every video in the run (video URLs, and videos found in channels, searches and playlists). Replies count toward this limit. 0 = no comments.

## `sortCommentsBy` (type: `string`):

Same as the sort menu above YouTube's comments.

## `includeReplies` (type: `boolean`):

Also scrape the replies of each comment (they count toward <b>Max comments per video</b>).

## `oldestCommentDate` (type: `string`):

A date (<code>2026-01-31</code>) or an age (<code>7 days</code>). YouTube shows comment dates as "3 days ago", so this is day/week/month precise. Forces <b>Newest first</b>.

## `commentsOnly` (type: `boolean`):

Output only comment rows. Use this when switching from a comments-only scraper.

## `deltaMode` (type: `boolean`):

Each run skips videos and comments that an earlier run with the same <b>Monitoring name</b> already returned. Schedule the run for daily/weekly monitoring.

## `monitorName` (type: `string`):

Any name, e.g. <code>competitors-weekly</code>. Runs with the same name share their memory.

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

Stops the run after this many rows in total (all inputs together). 0 = no limit (your spending limit still applies).

## `maxConcurrency` (type: `integer`):

How many channels / searches / videos are processed at the same time.

## `gl` (type: `string`):

2-letter country code (<code>US</code>, <code>DE</code>, <code>IN</code>, …) YouTube tailors search and hashtag results to. Default <code>US</code>. Texts stay English.

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

The default (Apify datacenter proxy) works for YouTube. If YouTube starts blocking it, the run switches to residential proxies on its own and says so in the log.

## `youtubeCookies` (type: `string`):

Only for <b>age-restricted videos and their comments</b>, which YouTube hides from logged-out visitors. Paste the cookies of a logged-in youtube.com tab (a cookie-extension JSON export, a cookies.txt file, or a <code>name=value; …</code> Cookie header). ⚠️ Requests are then made as that Google account: use a secondary account, not your main one - YouTube may ask it to verify itself or restrict it for automated use. Stored encrypted, never logged or saved to the dataset. Not needed for anything else.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.youtube.com/@MrBeast"
    }
  ],
  "maxResults": 20,
  "maxResultsShorts": 0,
  "maxResultStreams": 0,
  "maxPosts": 0,
  "maxPlaylists": 0,
  "includeVideoDetails": false,
  "includeRelatedVideos": false,
  "downloadSubtitles": false,
  "subtitlesLanguage": "en",
  "subtitlesFormat": "srt",
  "preferAutoGeneratedSubtitles": false,
  "saveSubsToKVS": false,
  "sortVideosBy": "NEWEST",
  "maxComments": 0,
  "sortCommentsBy": "NEWEST_FIRST",
  "includeReplies": false,
  "commentsOnly": false,
  "deltaMode": false,
  "maxItems": 0,
  "maxConcurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (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/@MrBeast"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("alom/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/@MrBeast" }] }

# Run the Actor and wait for it to finish
run = client.actor("alom/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/@MrBeast"
    }
  ]
}' |
apify call alom/youtube-scraper --silent --output-dataset

```

## MCP server setup

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