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 at a single $100 deposit and Scale at $500. Both are one-time and permanent — the tier is locked once earned and never downgrades if your balance falls — and there is no subscription and no minimum spend anywhere in this. 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 gives every project a fixed daily allowance of YouTube quota and no way to buy more. That allowance is the whole story of this market.
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.
That is roughly 3,000 free searches a month, hard-capped, and up to about 10,000 free reads a day. For a hobby project it is generous. For a dataset it runs out on day one. Checked on Google's own documentation 2026-09-08.
You cannot buy the 101st search
There is no rate, no billing path and no SKU for extra quota. Google's own wording is that to request additional quota beyond the default allocation you must first complete an audit showing your project complies with the YouTube API Services Terms of Service.
That is an audit and quota extension form, a compliance review, a periodic audit form afterwards, an appeals form if you fail, and a change-of-control form if your company is acquired. We sell the 101st search for $0.0002.
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.
Free beats every price — for the first 100 searches a day. Google’s own API is the cheapest thing on this table and it always will be, right up to the daily cap. The argument was never that we are cheaper than free. It is that there is no price at which you can buy the 101st search, and we sell it for $0.0002.
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
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
