How to Scrape YouTube Channel Videos in 2026 (Python, Node, curl)
Scrape every video from a YouTube channel with one GET request: handle in, unified video objects out, cursor pagination. Real endpoint, real response, and an honest look at the official 10,000-unit daily quota.
The fastest way to scrape a YouTube channel's videos in 2026 is a single GET request to a channel-videos API. Pass a handle, get back every recent video as a unified object with views, likes, comments, duration, and thumbnail already parsed. Here is the whole thing:
curl "https://www.socialcrawl.dev/v1/youtube/channel/videos?handle=@MrBeast&sort=latest" \
-H "x-api-key: $SOCIALCRAWL_KEY"
That returns a page of the channel's videos with engagement metrics attached, no Google Cloud project, no OAuth, and no quota accounting. The rest of this guide covers what the response looks like, how to paginate the full channel, when the official YouTube Data API is the better call and when it is not, error handling, and the credits math.
Stack: Python 3.10+ · requests · a SocialCrawl API key (free tier: 100 credits) · optionally pandas for CSV
Should you just use the official YouTube Data API?
Unlike Facebook or Reddit, YouTube's Data API v3 genuinely lets you read public channel videos with only an API key, no OAuth. So the honest question is not "can you" but "does the quota fit your workload." Three things push heavier jobs toward a third party.
First, the quota. Every project gets a default of 10,000 units per day. The costs are uneven: videos.list, channels.list, and playlistItems.list are 1 unit each, but search.list is 100 units. If your discovery step is search-based, that is roughly 100 searches a day, and each search caps at about 500 results. Raising the quota means submitting a compliance audit to Google with no guaranteed grant.
Second, the assembly. Listing a channel's videos properly is a three-call dance: channels.list to find the uploads playlist id (1 unit), then playlistItems.list to page through video ids (1 unit per 50), then videos.list to fetch view, like, and comment counts (1 unit per 50). It is cheap in units but it is three endpoints, three response shapes, and pagination you stitch yourself.
Third, the setup: a Google Cloud project, the YouTube Data API v3 enabled, and an API key, plus the audit if you outgrow the free quota.
A third-party YouTube API collapses all of that into one call that returns videos with stats already merged, in a schema shared with every other platform. This guide takes that route. If your volume is low and search-light, the official API is a perfectly good choice, covered in our YouTube Data API guide.
Is it legal to scrape YouTube?
Scraping publicly accessible pages has repeatedly survived legal challenge in US courts (the hiQ v. LinkedIn line of cases), and reading public YouTube metadata (titles, view counts, publish dates) sits on that precedent. That is not the whole story: YouTube's Terms of Service restrict automated access outside the API, video content and thumbnails carry copyright, and channel data can include personal information subject to GDPR and CCPA. Downloading video files is a separate, higher-risk activity from reading metadata. Read our legal and technical guide to social media scraping before shipping anything commercial, and talk to a lawyer if revenue depends on the answer. This section is a technical overview, not legal advice.
Setup: one key, no Google Cloud project
Install the only required dependency:
pip install requests
Get an API key at socialcrawl.dev, then Dashboard → API Keys. New accounts get 100 free credits, the channel-videos endpoint costs 1 credit per page, and credits never expire. Keep the key out of your source:
export SOCIALCRAWL_API_KEY=sc_your_api_key_here
There is no Google Cloud project, no API key to provision in a console, no OAuth consent screen, and no daily unit budget to track. One header does it.
Scraping a channel's videos
The endpoint is GET /v1/youtube/channel/videos. It takes either a handle (the @name) or a channelId, plus optional sort (latest or popular) and continuationToken for pagination.
import os
import requests
API_KEY = os.environ["SOCIALCRAWL_API_KEY"]
BASE = "https://www.socialcrawl.dev/v1"
resp = requests.get(
f"{BASE}/youtube/channel/videos",
params={"handle": "@MrBeast", "sort": "latest"},
headers={"x-api-key": API_KEY},
timeout=30,
)
payload = resp.json()
Here is a real, trimmed response from that exact call (one item shown):
{
"success": true,
"platform": "youtube",
"endpoint": "/v1/youtube/channel/videos",
"data": {
"items": [
{
"post": {
"id": "iYlODtkyw_I",
"url": "https://www.youtube.com/watch?v=iYlODtkyw_I",
"content": {
"text": "Survive 30 Days Chained To A Stranger, Win $250,000",
"thumbnail_url": "https://i.ytimg.com/vi/iYlODtkyw_I/hqdefault.jpg",
"duration_seconds": 2105
},
"author": { "username": "@MrBeast", "display_name": "MrBeast" },
"engagement": { "views": 75265598, "likes": 1514170, "comments": 86000 },
"published_at": "2026-06-29T00:38:22.000Z",
"ext": { "content_type": "video" }
},
"computed": { "engagement_rate": 0.02126, "estimated_reach": 90318718 }
}
],
"next_cursor": "sc.eyJ2Ijoy...",
"total": null
},
"credits_used": 1,
"credits_remaining": 99
}
The video comes back complete: engagement.views, engagement.likes, and engagement.comments are already merged into the one item, so there is no second videos.list call to make. The computed block adds an engagement_rate and an estimated_reach you would otherwise calculate yourself. The field names (content.text for the title, author, engagement, published_at) match the Reddit, Facebook, and TikTok post endpoints, so a parser transfers unchanged.
Paginating the whole channel
The response carries a pagination object with a next_cursor and a has_more flag. Pass the cursor back as the continuationToken parameter, and stop when has_more is false.
def scrape_channel_videos(handle: str, max_pages: int = 20) -> list[dict]:
"""Fetch a channel's videos, one page per credit."""
videos, cursor = [], None
for _ in range(max_pages):
params = {"handle": handle, "sort": "latest"}
if cursor:
params["continuationToken"] = cursor # pass next_cursor back
resp = requests.get(
f"{BASE}/youtube/channel/videos",
params=params,
headers={"x-api-key": API_KEY},
timeout=30,
)
payload = resp.json()
if not payload.get("success"):
raise RuntimeError(payload["error"]["message"])
videos.extend(payload["data"]["items"])
page = payload.get("pagination", {})
cursor = page.get("next_cursor")
if not page.get("has_more"):
break
return videos
print(len(scrape_channel_videos("@MrBeast")), "videos")
The max_pages guard matters for prolific channels: a decade-old channel paginates a long way, and each page is a credit. Encode your budget.
The same call in Node and curl
The endpoint, parameters, and envelope are identical across languages. Node:
const res = await fetch(
"https://www.socialcrawl.dev/v1/youtube/channel/videos?handle=@MrBeast&sort=latest",
{ headers: { "x-api-key": process.env.SOCIALCRAWL_API_KEY! } },
);
const { data, pagination } = await res.json();
console.log(data.items.length, "videos, more:", pagination.has_more);
curl, with a channelId instead of a handle:
curl "https://www.socialcrawl.dev/v1/youtube/channel/videos?channelId=UCX6OQ3DkcsbYNE6H8uQQuVA&sort=popular" \
-H "x-api-key: $SOCIALCRAWL_KEY"
Beyond the video list: comments and transcripts
Once you have video ids, the same key reaches the rest of a channel's data:
- Comments:
GET /v1/youtube/video/commentstakes a video URL or id and returns the comment list, paginating the same way. On the official API this iscommentThreads.list, 1 unit per page against your daily quota. - Transcripts:
GET /v1/youtube/video/transcriptreturns the spoken words as text, ideal for feeding an LLM. The official API has no transcript endpoint at all, so this is one you cannot do first-party. - Channel profile and search: the
channelandsearchendpoints round out discovery.
The full roster is on the YouTube platform page.
Handling errors and rate limits
Failures use the same envelope with success: false and a typed error object. The types you will actually meet:
| Error type | Status | What it means | Your move |
|---|---|---|---|
RESOURCE_NOT_FOUND | 404 | Channel deleted or handle typo'd | Skip it. Empty upstream refunds the credit. |
UPSTREAM_ERROR | 502 | YouTube hiccuped | Retry with backoff; credit refunded. |
SERVICE_UNAVAILABLE | 503 | Circuit breaker open | Honor the Retry-After header. |
CONCURRENCY_LIMIT | 429 | More than 50 concurrent requests / key | Cap your worker pool below 50. |
INSUFFICIENT_CREDITS | 402 | Balance below the call cost | Top up. |
Note what is not there: a 10,000-unit daily quota. The only throughput constraint is 50 concurrent requests per key, and empty-upstream 404s, 502s, and 503s automatically refund the credit. There is also a cache: request the same channel again inside the cache window and the response comes back with credits_used: 0. The full matrix is in the error handling docs.
Scraping YouTube at scale: the credits math
The channel-videos endpoint is 1 credit per page (roughly 30 videos), and the transcript and comment endpoints are 1 credit per page too.
| Workload | Requests | Credits |
|---|---|---|
| One channel, first page (~30 videos) | 1 | 1 |
| One channel, 20 pages (~600 videos) | 20 | 20 |
| 100 channels × 5 pages | 500 | 500 |
| 600 videos + transcripts on the top 50 | 20 + 50 | ~70 |
The free tier's 100 credits cover the first rows. Past that, pricing is pay-as-you-go and credits never expire: 2,500 credits is £15, and the Growth plan's 20,000 (£49) funds the 100-channel sweep many times over. Compare that to the official API's fixed 10,000 units a day, which you cannot buy your way past without an audit. For a no-code look at a single channel, the free YouTube channel viewer surfaces the same data in your browser, and the YouTube transcript generator turns any video into text.
Frequently asked questions
How do I scrape all videos from a YouTube channel?
Pass the channel handle to GET /v1/youtube/channel/videos, then loop, sending the response's next_cursor back as the continuationToken parameter until has_more is false. Each page returns about 30 videos with view, like, and comment counts already attached, for 1 credit. No Google Cloud project, no OAuth, no daily quota.
Can you scrape YouTube with the official API?
Yes, the YouTube Data API v3 reads public channel videos with just an API key, no OAuth. The catch is a default quota of 10,000 units per day, where search.list costs 100 units, and listing a channel's videos with stats takes three chained calls (channels.list, playlistItems.list, videos.list). A third-party API returns the same data in one call with no quota.
Is scraping YouTube legal?
Reading public YouTube metadata has meaningful precedent in its favor, but it depends on jurisdiction, data type, and access method, and YouTube's Terms restrict automated access outside the API. Video content and thumbnails carry copyright, and channel data can include personal information under GDPR and CCPA. Downloading video files is higher risk than reading metadata. Check YouTube's current terms and consult counsel for commercial use. This is a technical overview, not legal advice.
What is the YouTube Data API quota?
Every Google Cloud project gets a default of 10,000 units per day. Read calls like videos.list and playlistItems.list cost 1 unit, but search.list costs 100, which is why search-heavy workloads exhaust the quota fast. Raising it requires a compliance audit. A third-party YouTube API replaces the unit budget with per-credit pricing and no daily cap.
Can I get a YouTube video transcript by API?
Yes, with GET /v1/youtube/video/transcript, which returns the spoken words as text for 1 credit per page. The official YouTube Data API has no transcript endpoint, so this is data you cannot get first-party without scraping the caption track yourself.
How much does it cost to scrape YouTube?
The channel-videos, comments, and transcript endpoints each cost 1 credit per page. New accounts get 100 credits that never expire, then pricing is pay-as-you-go from £15 for 2,500 credits. Unlike the official API's fixed daily quota, credits let you scale a large backfill without an audit.
Does the same code scrape other platforms?
Almost. YouTube videos come back in the same canonical shape as Reddit, Facebook, and TikTok posts (content.text, author, engagement.views, published_at), so your parsing and export code transfers. The differences are the input parameter and the pagination token name per platform, both listed in the pagination docs.
Where to go from here
You now have a YouTube channel scraper that costs 1 credit per page, returns videos with stats already merged, and never touches a daily quota. Next steps: browse the other endpoints on the YouTube platform page, read the YouTube Data API guide for the first-party reference, or compare providers in best YouTube data APIs (2026). Start with the free tier: 100 credits, no card is about 3,000 videos, more than enough to find out whether the data answers your question.
Related posts
Best Amazon Product Data APIs: Pricing Compared (2026)
Amazon product API pricing compared across 7 providers in 2026. SocialCrawl, Rainforest, Oxylabs, Bright Data, Apify, ScraperAPI, and Canopy, ranked on price per request, field depth, and free tier.
Best App Store & Google Play Review APIs (2026): Pricing Compared
Apple's and Google's official APIs only return reviews for apps you own. Here are the APIs that read App Store and Google Play reviews for any public app, compared on price in 2026.
Best Facebook Data APIs for Developers (2026): Pricing Compared
The best Facebook data API in 2026 is SocialCrawl for unified public-page data without Graph API app review. 6 providers compared on pricing, coverage, and Ad Library access.
