Try it
Run a live YouTube request
One real call, no signup and no key. Search videos, channels or playlists and read the JSON we hand back.
Endpoints & Pricing
Four YouTube Endpoints, One Rate
Search, video, channel and playlist all bill the same per call — whichever endpoint you hit, and however many rows come back.
Search
GET /api/social/youtube/search- Videos, channels or playlists via
type num1–50,order,country,safedetails=trueadds each video's statistics
Video
GET /api/social/youtube/video- Up to 50 ids in one call via
ids - Statistics, tags, category and duration
isShortand a computedengagementRate
Channel
GET /api/social/youtube/channel- By id,
@handleor full channel URL - Subscriber, video and lifetime counts
include_videosadds recent uploads and cadence
Playlist
GET /api/social/youtube/playlist- By id, or a watch URL carrying
list= video_count1–50, default 50- Full video records, not just ids
One call is one charge, whatever it returns. A search asking for 50 rows costs exactly what a search asking for 1 costs, and a playlist walk of 50 video records is a single billed call. Two of the vendors in the comparison table below bill per video or per record instead, which is where a big pull gets expensive.
Growth unlocks with one qualifying $100 deposit, Scale with $500 and Enterprise with $1,000 for new credit. Existing credit keeps its original schedule, and there is no subscription or minimum spend. Refunded or charged-back amounts don't count toward your tier. New accounts get Free to start, shared across every endpoint, and all four YouTube endpoints can spend them.
Quick Start
YouTube Data in One Request
One header and a query string. Every endpoint answers with a flat object, not a nested resource envelope you have to unwrap first.
# Search. type=video is the default; channel and playlist are the other two. curl "https://apiserpent.com/api/social/youtube/search?q=react+hooks&num=10&order=viewCount" \ -H "X-API-Key: YOUR_API_KEY" # Up to 50 videos in ONE billed call — use ids, not a loop over id. curl "https://apiserpent.com/api/social/youtube/video?ids=dQw4w9WgXcQ,9bZkp7q19f0" \ -H "X-API-Key: YOUR_API_KEY" # A channel by handle, with its 10 most recent uploads and its posting cadence. curl "https://apiserpent.com/api/social/youtube/channel?id=@mkbhd&include_videos=true" \ -H "X-API-Key: YOUR_API_KEY" # A playlist, as full video records rather than bare ids. curl "https://apiserpent.com/api/social/youtube/playlist?id=PLexample&video_count=25" \ -H "X-API-Key: YOUR_API_KEY"
import requests BASE = "https://apiserpent.com/api/social/youtube" HEAD = {"X-API-Key": "YOUR_API_KEY"} # 1. Three pages of 50 rows = three billed calls, 150 rows. rows, token = [], None for _ in range(3): params = {"q": "sourdough starter", "num": 50, "order": "date"} if token: params["page_token"] = token data = requests.get(f"{BASE}/search", headers=HEAD, params=params, timeout=60).json() rows += data["results"] token = data.get("nextPageToken") if not token: break # 2. Statistics for 50 of them in ONE more call, not fifty. ids = ",".join(r["id"] for r in rows[:50]) stats = requests.get(f"{BASE}/video", headers=HEAD, params={"ids": ids}, timeout=60).json() for v in stats["results"]: print(v["title"], v["viewCount"], v["engagementRate"], v["durationFormatted"])
const res = await fetch( 'https://apiserpent.com/api/social/youtube/channel' + '?id=@mkbhd&include_videos=true&video_count=20', { headers: { 'X-API-Key': process.env.SERPENT_KEY } } ); const ch = await res.json(); console.log(ch.title, ch.subscriberCount, ch.videoCount); console.log('cadence:', ch.publishingFrequency); // needs 2+ dated uploads console.log('last upload:', ch.lastVideoDate); console.log('still active:', ch.isActive); // true within 14 days // The derived keys are only present when the rows carry a publish date — // a channel that has never uploaded gets the rows and no invented aggregates. for (const v of ch.recentVideos ?? []) { console.log(v.publishedAt, v.title, v.viewCount); }
{
"success": true,
"query": "react hooks",
"type": "video",
"results": [
{
"position": 1,
"id": "exampleVid01",
"type": "video",
"title": "React Hooks, the Whole Story",
"description": "Every hook in one sitting, with the rules that...",
"channelId": "UCexampleChannel00000001",
"channelTitle": "Example Dev",
"publishedAt": "2026-02-14T14:00:16Z",
"thumbnail": "https://i.ytimg.com/vi/exampleVid01/hqdefault.jpg",
"url": "https://www.youtube.com/watch?v=exampleVid01"
}
],
"totalResults": 1000000,
"nextPageToken": "CAMQAA",
"prevPageToken": null,
"meta": {
"elapsed": "2535ms",
"timestamp": "2026-09-08T10:14:15.354Z"
}
}
// GET /api/social/youtube/video — one flat record per id
{
"results": [
{
"id": "exampleVid01",
"title": "React Hooks, the Whole Story",
"tags": ["react", "hooks", "frontend"],
"categoryId": "28",
"duration": "PT21M13S",
"durationFormatted": "21:13",
"durationSeconds": 1273,
"isShort": false,
"viewCount": 1842911,
"likeCount": 64210,
"commentCount": 2184,
"engagementRate": 3.6
}
],
"totalResults": 1
}
Every field sits at one level. A row is title, thumbnail, url — there is no resource envelope to unwrap before you reach the value you asked for. engagementRate and durationSeconds are computed for you, so a sort by engagement is one line rather than a parse of an ISO 8601 duration string.
Data Fields
Every Field a YouTube Call Returns
Named JSON fields at one flat level. Nothing here needs a parser of your own, and the shape does not change between calls.
Search Row Fields
- results[].position
- results[].id
- results[].type
- results[].title
- results[].description
- results[].channelId
- results[].channelTitle
- results[].publishedAt
- results[].thumbnail
- results[].url
- totalResults, nextPageToken, prevPageToken
Video Fields
- id, title, description
- channelId, channelTitle
- publishedAt, thumbnail
- tags[], categoryId
- duration (ISO 8601)
- durationFormatted, durationSeconds
- isShort
- viewCount, likeCount, commentCount
- engagementRate
Channel Fields
- channelId, channelUrl, title
- description, customUrl, country
- publishedAt, keywords
- thumbnail, banner
- subscriberCount, videoCount, viewCount
- hiddenSubscriberCount, avgViewsPerVideo
- recentVideos[] (include_videos)
- publishingFrequency, lastVideoDate
- daysSinceLastVideo, isActive, avgEngagementRate
Request Parameters
- q (search query, required)
- type (video, channel, playlist)
- num (1–50, default 10)
- order (relevance, date, viewCount, rating, title)
- country (2-letter code)
- duration (any, short, medium, long — videos only)
- published_after (ISO 8601 date or datetime)
- safe (none, moderate, strict)
- page_token, details
- id / ids / handle / url / playlist_id
- include_videos, video_count (1–50)
Derived fields are only present when they can be honest. publishingFrequency needs at least two uploads carrying a publish date; lastVideoDate, daysSinceLastVideo, isActive and avgEngagementRate need at least one. A channel that has never uploaded gets its rows and no invented aggregates on top — no null-shaped placeholders, and never the string “NaN videos/month” that a naive average produces.
details=true merges each video's statistics into every search row, so one call gives you the row and its numbers together. It applies to type=video only. duration is likewise a video-only filter.
Why a YouTube API
What YouTube data is, and why teams use it
Google documents a default daily allocation for its YouTube Data API. Additional quota goes through its audit and extension process.
The daily allowance, in Google's own numbers
A project that enables Google's YouTube API gets a default allocation of 100 search calls a day, 100 uploads a day, and 10,000 units a day shared across every other endpoint. A search costs one of the 100. A video, channel or playlist read costs one unit out of the 10,000.
At the documented default, 100 searches a day is about 3,000 in a 30-day month. A project may request a higher allocation through Google's audit and quota process; check its current allocation in Google Cloud Console.
How to request more quota
Google does not publish a self-service per-call price for extra YouTube API quota. Its documented route for a project requesting more than the default is a compliance audit and quota extension form.
Serpent bills its own YouTube search requests by call: $0.20/1K on Default and $0.01/1K on Scale after a qualifying $500 deposit for new credit.
What the numbers are actually used for
Subscriber counts, upload cadence and per-video engagement are the three measures that decide whether a creator is worth paying, whether a competitor is still investing in a channel, and whether a topic is rising or already saturated.
avgViewsPerVideo, engagementRate, publishingFrequency and daysSinceLastVideo are computed for you, so those three questions are a field read rather than a pipeline.
What this is not
This returns metadata about public videos, channels and playlists. It does not return transcripts or captions, it does not download or re-host media, and it does not reach anything behind a sign-in.
Some vendors in the table below sell transcripts as a separate product or an add-on. If a transcript is what you need, that is a different purchase — we do not claim it and do not price it.
Price comparison
What YouTube Data Costs, Everywhere
Every vendor’s own lowest published rate, in the same unit, with what it takes to reach it. Only one is cheaper, and it is not for sale.
| Provider | Unit charged | Cost per 1,000 | What the lowest rate requires | Free tier |
|---|---|---|---|---|
| Google YouTube Data API v3 | quota units | Not for sale at any price | No rate, no billing path, no SKU. Extra quota needs an audit and a form. | 100 searches/day + 10,000 units/day |
| Serpent (ours) | per call, up to 50 rows | $0.01/1K calls | One $500 deposit, once. No monthly plan. | Free to start |
| ScrapingDog YouTube | per request, 5 credits | $0.136/1K requests | $30,000/month plan | 200 credits |
Apify streamers/youtube-scraper |
per video | $2.40/1K videos | Apify’s published “from” rate, and the lowest they print. Their actor FAQ quotes a higher figure for the same actor, so the page contradicts itself — we use the lower one. A cheaper Diamond rate exists but Apify publishes no price for that tier. | $5 credit/month |
| Bright Data YouTube | per record | $1.30/1K records | Scale plan at $499/month | 5,000 records/month |
| SerpApi YouTube engine | per search | $1.96/1K searches | $106,050/month plan | 250 searches/month |
Our figure is the Scale rate, so every competitor column shows that vendor’s lowest published rate too — not their entry rate. Our entry rate is $0.20/1K calls, which is 5× under ScrapingDog’s $1.00/1K entry — that entry rate is our own arithmetic off its Lite plan, $40 for 200,000 credits, at the 5 credits a YouTube request costs, so $40 buys 40,000 requests — 7.5× under Bright Data’s $1.50/1K pay-as-you-go and 125× under SerpApi’s $25.00/1K Starter. Growth at $0.02/1K beats ScrapingDog’s absolute floor of $0.136/1K by 6.8×, for a one-time $100 rather than $30,000 a month. ScrapingDog also sells a separate YouTube Transcript API at $0.027 per 1,000 requests on the same $30,000/month plan; we do not return transcripts, so it is not a like-for-like row and it is not in this table. Rates read from each vendor’s own pricing page on 2026-09-08.
Google's default quota is free. Its current documentation lists 100 search.list calls per day by default. Projects can request additional quota through an audit and extension form; Google does not publish a self-service per-call price for it. Serpent's separate YouTube search endpoint bills by call, starting at $0.20/1K on Default and reaching $0.01/1K on Scale after a qualifying $500 deposit for new credit.
Then check the unit. We bill per call, so a search returning 50 rows is one charge and a playlist of 50 videos is one charge. Apify bills per video and Bright Data bills per record, so a 50-row pull is fifty charges on their meter and one on ours. Four of the rates above also need a recurring plan to exist — $30,000, $999, $499 or $106,050 a month. Ours needs a $500 deposit, once, and nothing renews.
Use cases
What Teams Actually Pull YouTube Data For
Four jobs that account for most YouTube API traffic, and the endpoint and parameters each one needs.
Competitor channel tracking
One channel call with include_videos=true gives you subscriber count, lifetime totals, the last 20 uploads, the posting cadence and whether the channel is still active — in a single billed call.
Run it nightly across a list of rivals and diff subscriberCount and daysSinceLastVideo. That is a competitive dashboard for a fraction of a cent a night.
Topic and content research
order=viewCount with published_after set to the last 90 days shows what is working in a niche right now, not what worked three years ago. duration separates shorts from long-form.
Add details=true and every row arrives with its statistics attached, so you can rank by engagementRate without a second pass.
Creator vetting for sponsorships
Subscriber count alone is the number creators optimise. avgViewsPerVideo, engagementRate and avgEngagementRate against the subscriber base are the ones that predict whether a placement will actually land.
hiddenSubscriberCount tells you when the headline number is not published at all, so your scoring can branch instead of treating a zero as a real value.
Catalogue and playlist monitoring
The playlist endpoint returns full video records rather than bare ids, so a course, a release schedule or a curated series arrives already populated with titles, durations and statistics.
video_count caps the walk at up to 50, and when fewer come back than you asked for the response says so rather than quietly handing you a short list.
FAQ
YouTube API Questions
search.list calls, 100 videos.insert calls, and 10,000 units per day across other endpoints. The default is about 3,000 search calls in a 30-day month. Google does not publish a self-service per-call price for more quota; projects can request an extension through its audit and quota process. Check the current allocation in Google Cloud Console.
video, channel, playlist), num (1–50, default 10), order (relevance, date, viewCount, rating, title), country (2-letter code), duration (any, short, medium, long — videos only), published_after (ISO 8601 date or datetime, a bare date read as midnight UTC), safe (moderate is the default, plus strict and none), page_token for pagination, and details (adds each video's statistics to a search result).
id, title, description, channelId, channelTitle, publishedAt, one thumbnail URL, tags, categoryId, duration, durationFormatted, durationSeconds, isShort, viewCount, likeCount, commentCount and engagementRate. All in a flat JSON structure.
channelId, channelUrl, title, description, customUrl, publishedAt, thumbnail, banner, country, keywords, subscriberCount, viewCount, videoCount, hiddenSubscriberCount and avgViewsPerVideo. Set include_videos=true and it also returns recentVideos, plus publishingFrequency, lastVideoDate, daysSinceLastVideo, isActive and avgEngagementRate derived from the rows that carry a publish date. video_count sets how many recent uploads to include, from 1 to 50.
num from 1 to 50 and defaults to 10. The video endpoint takes a single id, or up to 50 comma-separated ids in one call. The channel endpoint takes video_count from 1 to 50 when include_videos is on. The playlist endpoint takes video_count from 1 to 50 and defaults to 50. Every one of those is a single billed call, so 50 rows cost exactly what 1 row costs.
nextPageToken field, and a prevPageToken. Pass the value as the page_token parameter on your next request to get the following page of results. Each page is a separate billed call.
Start using the YouTube API
free API calls, shared across every endpoint. No card, no Google Cloud project, no subscription. YouTube data from $0.01/1K calls.
Try for Free
