YouTube Scraper avatar

YouTube Scraper

Pricing

from $0.50 / 1,000 video (listing only)s

Go to Apify Store
YouTube Scraper

YouTube Scraper

⚡ Every YouTube field in one Actor — videos, channels, playlists, search, Shorts, comments, subtitles, hashtags — at 200+ videos/sec. Chrome TLS fingerprint, rotating residential IPs, full channel metadata on every row. Zero blocks, zero CAPTCHAs.

Pricing

from $0.50 / 1,000 video (listing only)s

Rating

0.0

(0)

Developer

VortexData

VortexData

Maintained by Community

Actor stats

1

Bookmarked

2

Total users

1

Monthly active users

15 days ago

Last modified

Share

📺 YouTube Scraper — fast, complete, residential-grade

Scrape videos, channels, playlists, search results, Shorts, live streams and comments from YouTube — at residential-proxy speed with a Chrome TLS fingerprint.

✨ Why this scraper

  • Complete data. Returns the full set: video metadata, channel /about metadata duplicated on every channel item, parsed descriptionLinks, hashtags, commentsCount, isMonetized, full thumbnails array, captions metadata, streamingData (opt-in), plus inline comments and subtitles.
  • Fast. ~85 videos/s from a channel, ~210 videos/s from a playlist, 50 watch records in parallel without throttling — benchmarked live.
  • Anti-detection by default. curl_cffi with impersonate="chrome" (real Chrome TLS/JA3 fingerprint) and a fresh Apify Residential session ID per HTTP request — every outbound call uses a different residential IP.
  • PoToken-proof subtitles. Automatically falls back to YouTube's iOS player API when the WEB caption baseUrl is empty (post-PoToken rollout), so subtitles actually download.
  • Channel /about enrichment. Every channel item carries channelDescription, channelDescriptionLinks, channelJoinedDate, channelLocation, channelTotalVideos, channelTotalViews, numberOfSubscribers, inputChannelUrl.
  • Comments inline. Walked through /youtubei/v1/next continuation — no separate actor needed.
  • Parallel everywhere. Multiple source URLs scrape concurrently. /about and tab listings on a channel fetch in parallel.

🚀 Quick start

  1. Paste a YouTube link (video, channel, playlist, search, Shorts) into Start URLsor type keywords into Search Queriesor drop channel handles (@MrBeast) into YouTube Handles.
  2. Click Start.
  3. Download results from the Dataset tab in JSON, CSV, Excel, XML or HTML.

The default settings already have a sample video URL pre-filled, so a one-click run returns one full video record immediately.

🎯 What you can scrape

Source URLWhat you get
https://www.youtube.com/watch?v=...Single video: title, description, likes, views, commentsCount, channel info, subscribers, hashtags, descriptionLinks, full thumbnails array, dates, captions metadata, isLive / isMonetized / isFamilySafe, optional streamingData
https://www.youtube.com/shorts/...Same shape as a normal video
https://www.youtube.com/@handle or /c/Name or /channel/UC...Channel /about metadata + every requested tab (videos / shorts / streams), each item enriched with channel-level fields
https://www.youtube.com/playlist?list=...Playlist videos with channelName, channelUrl, viewCount, relative date, thumbnail
https://www.youtube.com/results?search_query=...Search results with full listing-level fields
https://www.youtube.com/hashtag/...Hashtag feed
Search Queries inputSame as above, plus you can pick sort order / date / 4K / HD / CC / Live / etc.

⚙️ Input examples

Scrape one video, including subtitles & comments

{
"startUrls": [
"https://www.youtube.com/watch?v=dQw4w9WgXcQ"
],
"downloadSubtitles": true,
"subtitlesLanguage": "en",
"subtitlesFormat": "srt",
"downloadComments": true,
"maxComments": 200
}

Scrape an entire channel (videos + shorts + streams)

{
"youtubeHandles": ["@MrBeast"],
"maxResults": 200,
"maxResultsShorts": 50,
"maxResultStreams": 10,
"sortVideosBy": "POPULAR"
}

Search with filters (HD videos uploaded this week, sorted by views)

{
"searchQueries": ["climate change"],
"maxResults": 100,
"sortingOrder": "views",
"dateFilter": "week",
"isHD": true
}

Multi-source batch, with a global cap

{
"startUrls": [
"https://www.youtube.com/playlist?list=PL...",
"https://www.youtube.com/@apify/videos",
"https://www.youtube.com/results?search_query=apify"
],
"maxResults": 50,
"maxItems": 500,
"concurrency": 8
}

📤 Output example

{
"type": "video",
"id": "wwSzpaTHyS8",
"title": "Did The Future Already Happen? - The Paradox of Time",
"url": "https://www.youtube.com/watch?v=wwSzpaTHyS8",
"description": "Go to https://brilliant.org/nutshell/ to dive deeper...",
"descriptionLinks": [
{ "text": "https://brilliant.org/nutshell/", "url": "https://brilliant.org/nutshell/" }
],
"hashtags": ["#science"],
"keywords": ["physics", "time"],
"category": "Education",
"views": 14613126,
"likes": 461357,
"commentsCount": 18432,
"commentsTurnedOff": false,
"date": "2024-01-30",
"publishDate": "Jan 30, 2024",
"uploadDate": "Jan 30, 2024",
"duration": "00:12:35",
"durationSeconds": 755,
"thumbnailUrl": "https://i.ytimg.com/vi/wwSzpaTHyS8/maxresdefault.jpg",
"thumbnails": [
{ "url": "...hqdefault.jpg", "width": 168, "height": 94 },
{ "url": "...maxresdefault.jpg", "width": 1920, "height": 1080 }
],
"embedUrl": "https://www.youtube.com/embed/wwSzpaTHyS8",
"channel": {
"id": "UCsXVk37bltHxD1rDPwtNM8Q",
"name": "Kurzgesagt – In a Nutshell",
"url": "https://www.youtube.com/@kurzgesagt"
},
"numberOfSubscribers": 22500000,
"isLive": false,
"isPrivate": false,
"isUnlisted": false,
"isFamilySafe": true,
"isMonetized": true,
"playabilityStatus": "OK",
"availableCountries": ["US", "GB", "DE", "..."],
"captions": {
"captionTracks": [
{ "base_url": "...", "language_code": "en", "kind": null }
]
},
"subtitles": [
{ "type": "manual", "language": "en", "format": "srt", "content": "1\n00:00:02,440 --> 00:00:09,520\nDo your past..." }
],
"comments": [
{
"id": "Ug...",
"author": "@kelving420",
"text": "The fact they can use all of these trademarked characters...",
"likeCount": 16,
"replyCount": 16,
"publishedTime": "3 weeks ago"
}
],
"fromYTUrl": "https://www.youtube.com/watch?v=wwSzpaTHyS8",
"status": "OK"
}

When scraping a channel, each item additionally carries:

"channelDescription": "...",
"channelDescriptionLinks": [{"text": "...", "url": "https://..."}],
"channelJoinedDate": "Feb 1, 2015",
"channelLocation": "United Kingdom",
"channelTotalVideos": 418,
"channelTotalViews": "2,473,486,020",
"inputChannelUrl": "https://www.youtube.com/@RickAstleyYT/about"

⚡ Performance (live benchmark)

WorkloadItemsTimeRate
Channel videos (with continuation)1001.17s85 vid/s
Playlist (with continuation)1000.47s210 vid/s
Search results (with continuation)1001.49s41 vid/s
3 listings in parallel1801.07s167 vid/s
8 channels × 200 videos in parallel12942.0s656 vid/s
500 comments via /next continuation5003.3s150 com/s
Single full /watch record10.81s

🧰 Advanced options

  • includeStreamingData — attach raw playerResponse.streamingData (mp4 formats, adaptive formats, URLs). Off by default because most format URLs are signature-protected and the payload is large.
  • saveSubsToKVS — write subtitles to the key-value store, keep the dataset record slim.
  • concurrency — number of in-flight HTTP requests. Default 5; the actor is happy at 16+.
  • maxItems — global cross-source cap (e.g. set 1000 to stop the run after 1000 items regardless of how many start URLs).
  • sortVideosBy — channel-tab sort: NEWEST, POPULAR, OLDEST.

🌍 Country / language (gl / hl)

YouTube respects the gl=US / hl=en URL parameters for results localization. The actor threads them through to:

  • Every HTML fetch (appended as query parameters)
  • The Accept-Language header
  • The Innertube context.client.gl / hl for /browse, /search, /next, /player continuation calls
  • The residential proxy's country routing — picking gl=de means traffic exits from a German residential IP and you get German-localized results.

❓ FAQ

Why is getTrending returning nothing? YouTube removed the public Trending feed for unauthenticated visitors in 2024 — /feed/trending now serves a "Try searching to get started" placeholder. As a workaround, use searchQueries with "sortingOrder": "views" and "dateFilter": "today".

Why is streamingData empty in my output? It's off by default — flip includeStreamingData: true. Note that for most popular videos the playback URLs inside are signature-ciphered and need a JS decipher step (see signatureCipher vs url keys).

Why are some subtitle tracks missing for a video? Either the video has no captions, or YouTube returned an empty body for the WEB caption URL (post-PoToken rollout). The actor auto-falls back to the iOS-client player, which fixes the vast majority of cases.

Why location: null? The video's uploader didn't tag a location. The field exists on YT's microformat but is rarely populated.

Can I scrape dislikes? No — YouTube made dislike counts non-public in 2021.

What's isMonetized based on? The actor checks playerResponse.adPlacements and playerResponse.playerAds. If either is non-empty, the video runs ads and is monetized.

📞 Support

Open an issue on the Issues tab with a sample input that reproduces the problem. We aim to respond same-day for blockers.