YouTube Scraper: Search, Channels, Playlists & Videos
Pricing
from $2.00 / 1,000 video scrapeds
YouTube Scraper: Search, Channels, Playlists & Videos
Scrape YouTube search results, channels, playlists and individual videos in one run. Title, views, likes, duration, publish date, description, tags, channel stats and thumbnails. No API key, no daily quota, no OAuth — unlike the official Data API.
Pricing
from $2.00 / 1,000 video scrapeds
Rating
0.0
(0)
Developer
Arman Hossain
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
3 days ago
Last modified
Categories
Share

YouTube Scraper takes search terms, channel handles, playlist URLs and video URLs in the same run and returns one record shape for all of them: title, exact view count, exact like count, duration, publish date, full description, tags, channel stats and thumbnails.
Every record carries type, id and url, so a search result, a channel's upload history and a one-off video lookup all land in the same table. No API key, no daily quota, no OAuth, no proxy setup and no browser.
Agent skill: SKILL.md
https://api.apify.com/v2/key-value-stores/t7YoTxpZEJOWvw4Ug/records/youtube-scraper.md
What you get
One record per video, short, channel or playlist. type tells them apart; every key exists on every record, and null means YouTube does not publish that field for that item.
| Output field | Meaning |
|---|---|
type | video, short, channel or playlist |
id | Video ID, channel ID or playlist ID. Your join key |
url | Canonical YouTube link, built from the ID |
title | Video, channel or playlist title |
input | The search term or URL that produced this row |
position | Rank within that input |
description | Full video description, the channel's About text, or the playlist blurb |
viewCount | Exact when video details are on. viewCountIsExact tells you which you got |
viewCountIsExact | true for a precise figure, false for one parsed from a rounded label |
likeCount | Exact like count. null when the creator has hidden likes, never 0 |
durationSeconds, duration | 213 and 3:33 |
publishedAt | ISO 8601 publish time. Present when video details are on |
publishedText | YouTube's own relative string, e.g. 4 years ago |
isLive, wasLive | Currently streaming, and ever streamed |
tags | The uploader's own keywords. Video details only |
categoryName | Music, Education, and so on. Video details only |
thumbnailUrl | Largest thumbnail offered |
channelId, channelName, channelHandle, channelUrl | Who published it |
subscriberCount | Approximate. YouTube publishes only a rounded figure |
badges | 4K, CC, LIVE |
videoCount | Uploads on a channel, or entries in a playlist |
totalViewCount | Lifetime views for a channel, or for a playlist |
joinedDate, country | Channel only |
avatarUrl, bannerUrl, isVerified, links | Channel only |
playlistId, firstVideoId | Playlist only |
scrapedAt | Run timestamp |
There is no commentCount. Nothing this Actor reads publishes one, and a column that is permanently null is worse than an honest omission.
A RUN_SUMMARY record in the key-value store holds records saved by type, how many view counts were exact, how many videos were checked and found to have likes hidden, the filters that were applied, how many rows were removed by each filter and how many could not be date-checked at all, any input that ran into the paging ceiling before its cap was met, every failure with its reason, and any result card the parser did not recognise.
Input
| Field | Type | Default | Notes |
|---|---|---|---|
searchQueries | array | [] | Search terms, exactly as typed into YouTube's search bar |
startUrls | array | [] | Video, channel, playlist or @handle URLs, mixed freely. Bare IDs and youtu.be links work too |
maxResultsPerInput | integer | 50 | Cap on the total records one query or URL may produce, across every requested resultTypes. The main cost control, since charging is per record |
resultTypes | array | ["video"] | Any of video, short, channel, playlist. Decides what a search keeps, and which of a channel's tabs are read |
sortBy | string | relevance | relevance, date, views, rating. Search terms only |
uploadedAfter | string | A date (2026-01-15) or a window (30 days) | |
videoDuration | string | any | short (under 4 min), medium (4 to 20), long (over 20). Search terms only |
videoFeatures | array | [] | hd, 4k, subtitles, creativeCommons, live, 360, hdr, combined with AND. Search terms only |
includeVideoDetails | boolean | true | The accuracy dial. On: exact view and like counts, full description, tags, category, exact publish date, one extra lookup per video. Off: faster and cheaper in time, with YouTube's rounded display counts and no publish date |
country | string | US | Two-letter code. Changes which results rank |
language | string | en | Two-letter code. Changes YouTube's interface strings, including the wording of relative dates |
At least one of searchQueries or startUrls is required. A run with neither fails with a named error rather than returning nothing.
{"searchQueries": ["web scraping tutorial"],"startUrls": ["https://www.youtube.com/@Apify"],"maxResultsPerInput": 100,"resultTypes": ["video"],"uploadedAfter": "90 days","sortBy": "views"}
Output
{"type": "video","id": "dQw4w9WgXcQ","url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ","title": "Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)","input": "https://www.youtube.com/watch?v=dQw4w9WgXcQ","position": 1,"description": "The official video for “Never Gonna Give You Up” by Rick Astley...","viewCount": 1802092331,"viewCountIsExact": true,"likeCount": 19322530,"durationSeconds": 213,"duration": "3:33","publishedAt": "2009-10-25T06:57:33.000Z","publishedText": null,"isLive": false,"wasLive": false,"tags": ["rick astley", "Never Gonna Give You Up", "rickroll"],"categoryName": "Music","thumbnailUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg","channelId": "UCuAXFkgsw1L7xaCfnd5JJOw","channelName": "Rick Astley","channelHandle": "@RickAstleyYT","channelUrl": "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw","subscriberCount": 4530000,"badges": [],"videoCount": null,"totalViewCount": null,"joinedDate": null,"country": null,"avatarUrl": null,"bannerUrl": null,"isVerified": false,"links": [],"playlistId": null,"firstVideoId": null,"scrapedAt": "2026-08-09T01:14:02.000Z"}
A channel record fills the channel half of the same shape:
{"type": "channel","id": "UCTgwcoeGGKmZ3zzCXN2qo_A","url": "https://www.youtube.com/channel/UCTgwcoeGGKmZ3zzCXN2qo_A","title": "Apify","channelName": "Apify","channelHandle": "@Apify","description": "Apify equips you and your AI agents with thousands of ready-to-run tools...","subscriberCount": 17400,"videoCount": 268,"totalViewCount": 11646145,"joinedDate": "2017-01-04","country": "Czechia","avatarUrl": "https://yt3.googleusercontent.com/...","bannerUrl": "https://yt3.googleusercontent.com/...","isVerified": false,"links": [{ "title": "Browse tools", "url": "apify.com/store" }]}
Use cases
- Creator discovery. Search a topic, keep
channelresults, and rank by subscribers and lifetime views. - Topic tracking. Run a set of queries on a schedule with
uploadedAfter, and watch what gets published on a subject. - Channel analysis. Point at a handle and pull the whole upload history with exact view and like counts, then look at the trend.
- URL enrichment. Hand it a list of video URLs from a spreadsheet and get structured metadata back, one row each.
- Playlist inventory. Turn a course playlist into a table of videos, durations and view counts.
Limits and behaviour
- Subscriber counts are rounded, by YouTube.
17.4K subscribersis the most precise figure published anywhere, sosubscriberCountis17400, not the true number. It cannot be made exact. subscriberCounton a search result needsincludeVideoDetails. A search listing does not carry it, so it is looked up once per channel and reused. With details off, search rows havesubscriberCount: null; a channel's own pages always carry it either way.maxResultsPerInputis a total, not a per-type quota. One channel URL asked for["channel", "video", "short", "playlist"]with a cap of 200 returns at most 200 rows in all, filled in that order — not 200 of each. The cap is what you are charged for, so it is never exceeded.- View counts are exact only with
includeVideoDetailson. With it off,viewCountcomes from a display label such as474K viewsandviewCountIsExactisfalse. Never round silently: check the flag. likeCountneedsincludeVideoDetails. A listing carries no like figure at all, in any form, so with details off the field isnullon every row rather than a rounded guess.likeCountisnullwhen the creator hides likes. That is not zero, and treating it as zero would misreport an unliked video.publishedAtisnullwithout video details. A listing only carries4 years ago, and turning that into a timestamp would be precision this Actor does not have.publishedTextcarries YouTube's own wording instead.uploadedAfteris exact with details on, approximate without. With details off it is applied against the relative string, so a video near the boundary can fall either way. If that string cannot be read at all — which is what happens whenlanguageis noten— the row is kept rather than dropped, and counted inRUN_SUMMARY.datesUnverifiableso a result set that overshoots the window says why. AnuploadedAftervalue the Actor cannot parse stops the run before anything is fetched or charged.typeisshortonly when the source said so. A/shorts/URL or a card from a Shorts shelf. A short clip found through search staysvideo.commentCountis not returned. See above.- A single input is walked for a bounded number of pages. Very large caps on a broad search can stop short of
maxResultsPerInput; when that happens the input is listed inRUN_SUMMARY.truncatedByPageCaprather than quietly returning a short answer. Split the work across narrower queries to go deeper. - No video, audio or subtitle downloads. This Actor returns metadata. Nothing is streamed, saved or converted.
- Deleted, private and region-locked videos are named failures, listed in
RUN_SUMMARY.failures, not blank rows. One bad URL never ends a run. - Results churn. YouTube reorders its own search results between requests. Join on
idand treat a single absence as noise. - Rows are deduplicated within an input, not across them. Two search terms that both surface the same video produce two rows, each with its own
inputandposition. Deduplicate onidyourself if you merge inputs. - Non-English runs return YouTube's own strings. With
languageset to something other thanen,publishedTextcomes back localised and any figure derived from a display label may benull. Turn video details on for language-independent numbers. - Public data only. No authentication, and nothing that gets around access controls.
FAQ
Do I need a YouTube API key or a Google Cloud project? No. You supply no credentials.
How does this compare with the official Data API's quota? There is no daily unit budget to plan against here. You are billed per record returned, so a 1,000-video run costs the same whether it is your first of the day or your fiftieth.
Why is a view count a few hundred off from what the web page shows? YouTube's own counters update on a delay and are not synchronised across surfaces. With includeVideoDetails on you get the precise figure YouTube itself reports for the video at that moment.
How do I scrape a whole channel? Put the channel URL or @handle in startUrls and raise maxResultsPerInput past the channel's upload count. Set resultTypes to ["video"] for uploads, add "short" for its Shorts, "playlist" for its playlists, or "channel" for a single row about the channel itself. Remember the cap covers all of them together, so raise it if you ask for more than one.
Can I get comments or transcripts? No. Those are separate products with a different shape.
Why is likeCount null on some videos? The creator switched likes off. The field stays null rather than reporting a zero that is not true.
Can I mix inputs? Yes. Search terms, channel handles, playlist URLs and video URLs can all go into one run, and they produce the same record shape.
Can I plug it into something else? Yes. Apify API, the client libraries, webhooks, scheduled runs, dataset exports to JSON, CSV or Excel, or MCP. The output is structured JSON.
API example
curl -X POST "https://api.apify.com/v2/acts/arman-bd~youtube-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \-H "Content-Type: application/json" \-d '{"searchQueries": ["web scraping tutorial"],"maxResultsPerInput": 50,"resultTypes": ["video"],"sortBy": "views","uploadedAfter": "365 days"}'
JavaScript example
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_TOKEN' });const run = await client.actor('arman-bd/youtube-scraper').call({startUrls: ['https://www.youtube.com/@Apify'],maxResultsPerInput: 200,resultTypes: ['video'],});const { items } = await client.dataset(run.defaultDatasetId).listItems();for (const v of items) console.log(`${v.title} — ${v.viewCount} views, ${v.likeCount ?? 'likes hidden'}`);