YouTube
YouTube channels, videos, comments, shorts, playlists, community posts, transcripts, media files, and search through one unified API
The widest surface on the API after LinkedIn: every tab of a channel, full video detail, threaded comments, two kinds of search, trending, transcripts and subtitle files, the raw audio/video/thumbnail streams, and batch endpoints that take a thousand ids at a time.
Base URL: /v1/youtube/...
Choosing between /v1/youtube/video/subtitles (1cr caption files) and
/v1/youtube/video/transcript (3cr cleaned transcript)? See Which endpoint
should I use?.
How do I get started with YouTube data?
1. Fetch a profile
curl "https://www.socialcrawl.dev/v1/youtube/channel?handle=MrBeast" \
-H "x-api-key: YOUR_API_KEY"2. Fetch their content
curl "https://www.socialcrawl.dev/v1/youtube/channel/videos?handle=MrBeast" \
-H "x-api-key: YOUR_API_KEY"3. Read computed fields
When an endpoint supports a computed field and the required source inputs are present, the unified response includes that optional field. Depending on the endpoint, optional fields can include engagement_rate, language, content_category, and estimated_reach. See Computed fields for formulas, clamping rules, and null semantics.
A channel has five tabs, and each has its own endpoint
GET /v1/youtube/channel/videos returns regular uploads only. Everything else on a channel lives behind its own call, and this is the single most common cause of "where did the rest of their content go":
| What you want | Endpoint |
|---|---|
| The account snapshot | GET /v1/youtube/channel |
| Regular uploads | GET /v1/youtube/channel/videos |
| Shorts | GET /v1/youtube/channel/shorts |
| Live and past streams | GET /v1/youtube/channel/lives |
| Playlists | GET /v1/youtube/channel/playlists |
| Text and image posts | GET /v1/youtube/channel/community-posts |
All five channel-scoped endpoints take either channelId or handle (one is required), and all cost 1 credit on a plain call. channel additionally accepts a url. On the videos, Shorts and live lists, include=channel adds the channel's subscriber count to every row for 1 more credit, and on the live list include=engagement adds the like and comment counts for at most 5 more. They page with continuationToken, YouTube's own token rather than the universal cursor: pass back what the previous response returned.
channel/videos returns light rows by default. Add includeExtras=true to fill in post.engagement.likes, post.engagement.comments, and post.ext.description on each row. It slows the response slightly but saves a video call per row.
# Shorts, not uploads
curl "https://www.socialcrawl.dev/v1/youtube/channel/shorts?handle=MrBeast" \
-H "x-api-key: YOUR_API_KEY"
# Uploads with engagement counts attached
curl "https://www.socialcrawl.dev/v1/youtube/channel/videos?handle=MrBeast&includeExtras=true&sort=popular" \
-H "x-api-key: YOUR_API_KEY"GET /v1/youtube/profile/full (5cr) collapses the first two rows into one call: the channel, its recent videos, and computed metrics. Two average engagement rates (avg_engagement_rate over view counts, avg_engagement_rate_by_followers over the subscriber count), posting cadence with the window it was measured over, the top post, and the format mix. posts sets how many videos to average over (1-100, default 25). The profile leg is the only critical one, so a failure to fetch videos still returns the profile with null post-dependent metrics and a legs[] explaining why.
Two searches, and they return different things
GET /v1/youtube/search(1cr) is the general one. It returns every content kind (videos, channels, playlists, shorts, live streams) withuploadDate,sortBy,type,duration, andregionfilters.GET /v1/youtube/search/advanced(1cr) returns videos only, but with the full filter set:published_after/published_beforewindows,license,category,event_type,video_caption,video_definition,video_dimension,video_embeddable,topic_id,locationwithlocation_radius,safe_search, and more. Reach for it when a plain keyword search is too blunt, and forsearchwhen you need channels or playlists back too.
Both search calls are metered: the base page is 1 credit and the optional extras are added on top. On search/advanced, includeExtras=true adds a flat 5 credits to fill the page with view, like, and comment counts, because that is a batch call under the hood; the page caps at 50 results upstream, so the increment is a single flat +5, never a multiple. On both calls, include adds at most 5 credits per value (see Subscriber counts next to search results below). So search/advanced is 1, 6 or 11 credits, and search is 1, 6 or 11.
Two more search surfaces: GET /v1/youtube/search/hashtag (1cr) reads a hashtag feed rather than a keyword query, with type=shorts to restrict it, and GET /v1/youtube/search/suggestions (1cr) returns YouTube's own autocomplete list for a partial query, the cheapest keyword-research call on the platform.
search's sortBy=popular is not a view-count sort. It is a
popularity-weighted ranking, and results do not come back in descending view
order, a new york search returned 9.5M, then 502.9M, then 66K views in that
order, on 4 of 4 test keywords. It also caps the page at roughly 20 results
and cannot be combined with type=shorts (that pair is rejected with a
400). For a view-faithful ordering use search/advanced with
order=viewCount&includeExtras=true, then sort the page yourself on the
returned engagement.views. Separately, search's duration filter is
currently not applied by the provider and can degrade the type filter.
Filter client-side on post.content.duration_seconds instead.
# Videos from a date window, with counts hydrated
curl "https://www.socialcrawl.dev/v1/youtube/search/advanced?query=ai%20agents&published_after=2026-06-01&order=viewCount&includeExtras=true" \
-H "x-api-key: YOUR_API_KEY"
# What does YouTube think people are searching for?
curl "https://www.socialcrawl.dev/v1/youtube/search/suggestions?query=how%20to%20train" \
-H "x-api-key: YOUR_API_KEY"One video, and everything hanging off it
GET /v1/youtube/video(1cr), the complete record from a videourl: title, view/like/comment counts, description, tags, duration, channel, publish date. List endpoints return lighter rows without the description or tags, so this is the call when those matter.GET /v1/youtube/video/comments(1cr): top-level comments with author, text, like count, reply count, and timestamp.order,searchTerm, andmax_resultsnarrow it.GET /v1/youtube/video/comment/replies(1cr), one thread opened up. It takes thecontinuationTokenthatvideo/commentsreturned for that comment, not a comment id, and you keep paging until no replies remain.GET /v1/youtube/video/transcript(3cr), the spoken words as timestamped segments with language, word count, and speech rate. A video without captions returns a404naming the reason; that is the expected result, not a failure.GET /v1/youtube/video/subtitles(1cr), the caption track files instead: language code and name, format, and a direct download URL, auto-generated tracks included. Cheaper thantranscriptwhen you want files rather than text.GET /v1/youtube/video/sponsors(10cr): whether a video carries a paid-promotion disclosure, plus the brands likely sponsoring it, each with supporting evidence and a confidence score. Sponsors are inferred from the description, links, promo codes, and transcript, not stated by YouTube, which is why every row carries confidence.GET /v1/youtube/video/audio(5cr),GET /v1/youtube/video/files(5cr),GET /v1/youtube/video/thumbnails(1cr), the downloadable streams. Audio gives mime type, bitrate, quality, sample rate and channels; files gives resolution, quality label, frame rate and bitrate; thumbnails gives every available size with width, height, and format.
The media URLs from video/audio and video/files are time-limited.
Fetch them immediately; do not store them in a database and expect them to
resolve later. Store the video id and re-request when you need the bytes.
# The whole comment tree on one video
curl "https://www.socialcrawl.dev/v1/youtube/video/comments?url=https://www.youtube.com/watch?v=dQw4w9WgXcQ&order=top" \
-H "x-api-key: YOUR_API_KEY"
# Then open one thread with the token that came back
curl "https://www.socialcrawl.dev/v1/youtube/video/comment/replies?continuationToken=TOKEN_FROM_PREVIOUS_RESPONSE" \
-H "x-api-key: YOUR_API_KEY"Comments from a date window
There is no date parameter on video/comments, because YouTube exposes none for comments, a server-side filter would read the same pages at the same cost. What makes a window pull work instead is that order=newest is an exact sort: rows arrive newest-first on comment.published_at with per-second timestamps, and each next page continues strictly older with no overlap.
So to pull, say, the last two years of comments on a video:
- Request
order=newest, up to 100 comments per credit. - Keep rows where
comment.published_atis on or after your cutoff. - Stop paging when the last row of a page is older than the cutoff.
The one row that can defy the sort is a pinned comment, which YouTube serves first regardless of order, so filter rows by timestamp (step 2) rather than stopping at the first old row you see, and step 3 stays correct.
curl "https://www.socialcrawl.dev/v1/youtube/video/comments?url=https://www.youtube.com/watch?v=dQw4w9WgXcQ&order=newest" \
-H "x-api-key: YOUR_API_KEY"The same shape works on the replies side: video/comment/replies rows carry the same comment.published_at, so apply the cutoff to the rows as you drain each thread.
Playlists and community posts
GET /v1/youtube/playlist and GET /v1/youtube/playlist/items (1cr each) both take a playlist_id and return the same rows from the same source, in playlist order: video id, title, thumbnail, the video's own channel (post.author.display_name, post.ext.channel_id) and its publish date, with the position and the insertion time on post.ext. On a plain call neither carries view, like or comment counts or durations, because YouTube's playlist listing does not include them. Add include=engagement and every row gets them in the same call from the per-video lookup, and include=channel adds each video's channel subscriber count: at most 5 credits per join for a 50-row page, refunded for anything that could not be filled. The one difference between the two endpoints is availability: playlist has a second source behind it, so prefer it when uptime matters.
GET /v1/youtube/community-post (1cr) takes a single post url; GET /v1/youtube/channel/community-posts lists them for a whole channel.
Trending
GET /v1/youtube/videos/trending (1cr) takes region, category, language, and max_results. This is the filterable one. GET /v1/youtube/shorts/trending (5cr) is a Shorts snapshot and takes only include, so it is one global list rather than a per-country view. Both accept include=channel, which adds each row's channel subscriber count for at most 5 more credits on trending videos and 10 on trending Shorts, whose page runs to about 70 rows.
Batch: one call, up to a thousand ids
Three POST endpoints take a JSON body when you already hold ids and want to stop calling the singular endpoint in a loop:
POST /v1/youtube/videos: up to 1000 video ids, each row the same object/v1/youtube/videoreturns. Ids that do not resolve are simply absent from the list.POST /v1/youtube/channels: up to 1000 channel ids, each row the same channel object/v1/youtube/channelreturns, subscriber count included (author.followers). Ids that do not resolve are absent from the list rather than returned empty, so join onauthor.id, never on array position, the response can be shorter than the request. Note that only the singularchannelendpoint accepts a handle or URL; the batch takes bareUC…ids and rejects anything else with a400before billing.POST /v1/youtube/transcripts: up to 100 video ids, one transcript row each with the caption language it resolved to and anokor not-found status. A video without captions comes back not-found rather than failing the request, and failed ids are refunded. Flat 3cr.
videos and channels are metered per chunk of 50 ids at 5 credits a chunk: 50 ids is 5cr, 200 ids is 20cr, the full 1000 is 100cr. The charge is per chunk regardless of how many ids in it resolve, so there is no per-id refund on these two.
curl -X POST "https://www.socialcrawl.dev/v1/youtube/transcripts" \
-H "x-api-key: YOUR_API_KEY" \
-H "content-type: application/json" \
-d '{"ids":["dQw4w9WgXcQ","9bZkp7q19f0"],"language":"en"}'Subscriber counts next to search results
Add include=channel and every result carries its channel's subscriber count on post.ext.author_followers, in the same call. Add engagement too and Shorts results, which arrive without a channel, get one first.
curl "https://www.socialcrawl.dev/v1/youtube/search?query=iphone17&type=shorts&include=engagement,channel" \
-H "x-api-key: YOUR_API_KEY"include=engagement fills the like and comment counts, the duration, the exact publish time and post.ext.channel_id from the per-video lookup. include=channel then adds the subscriber count and fills the channel's name and avatar where a row lacks them. Each join costs 1 credit per distinct video or channel it filled, and never more than 5 per 50. A page of Shorts with both costs at most 11 credits, the same as searching, resolving the videos and resolving the channels in three separate calls. Anything that could not be filled is refunded, and the hydration block on the response lists the rows, lookups, credits kept and milliseconds.
The same two values work on search/hashtag, playlist, playlist/items and channel/lives. include=channel alone works on search/advanced, videos/trending, shorts/trending, channel/videos and channel/shorts. On the three channel lists every row is the same channel, so the join is one lookup and costs 1 credit.
Which surface carries the channel id on a plain call:
| Search call | Carries post.ext.channel_id? |
|---|---|
search?type=videos | Yes, on every result |
search/advanced | Yes, on every result, no includeExtras needed |
search?type=shorts | No, until include=engagement joins it onto every row |
Shorts results carry no creator on a plain call. YouTube's Shorts shelf
ships the video without a channel object, so post.author.username,
post.author.display_name, post.author.avatar_url, and
post.ext.channel_id are null on every type=shorts result, and
includeExtras=true does not change it. include=engagement fills the
channel id and name on every one from the per-video lookup.
For a crawl that meets the same channels on many pages, it is cheaper to collect the channel ids across the whole run, deduplicate them, and resolve them once: POST /v1/youtube/channels takes up to 1,000 ids at 5 credits per 50.
curl -X POST "https://www.socialcrawl.dev/v1/youtube/channels" \
-H "x-api-key: YOUR_API_KEY" \
-H "content-type: application/json" \
-d '{"ids":["UCn9l4gU5mkmmlC2eiVu0LHw","UC_x5XG1OV2P6uZZ5FSM9Ttw"]}'author.followers is YouTube's own published number, and YouTube rounds it
to three significant figures above 1,000 subscribers. You will see
12,800,000 and 85,700 and 1,240, never the digit-exact figure behind them.
That rounding is YouTube's, applied to everyone, so there is no exact count
being withheld from you; below 1,000 subscribers it is exact. Channels at or
above 1,000 subscribers also set author.ext.followers_approximate to true.
A channel that hides its count entirely sets
author.ext.hiddenSubscriberCount to true, which is the signal to drop it
from a ratio rather than treat a zero as real.
What YouTube data can I access?
29 endpoints available.
| Endpoint | Path | Credit Tier |
|---|---|---|
| Get YouTube channel info | /v1/youtube/channel | standard (1cr) |
| List a YouTube channel's community posts | /v1/youtube/channel/community-posts | standard (1cr) |
| List a YouTube channel's live streams | /v1/youtube/channel/lives | standard (1-7cr)metered |
| List a YouTube channel's playlists | /v1/youtube/channel/playlists | standard (1cr) |
| List YouTube channel shorts | /v1/youtube/channel/shorts | standard (1-2cr)metered |
| List YouTube channel videos | /v1/youtube/channel/videos | standard (1-2cr)metered |
| Get YouTube community post | /v1/youtube/community-post | standard (1cr) |
| Get YouTube playlist | /v1/youtube/playlist | standard (1-11cr)metered |
| List the videos in a YouTube playlist | /v1/youtube/playlist/items | standard (1-11cr)metered |
| YouTube profile, recent posts, and computed analytics in one call. | /v1/youtube/profile/full | standard (5cr) |
| Search YouTube | /v1/youtube/search | standard (1-11cr)metered |
| Advanced YouTube video search | /v1/youtube/search/advanced | standard (1-11cr)metered |
| Search YouTube by hashtag | /v1/youtube/search/hashtag | standard (1-11cr)metered |
| Get YouTube search suggestions | /v1/youtube/search/suggestions | standard (1cr) |
| Up to 100 YouTube video ids → one transcript per row, failed ids refunded. | /v1/youtube/transcripts | standard (3-300cr)metered |
| Get YouTube video details | /v1/youtube/video | standard (1cr) |
| List YouTube comment replies | /v1/youtube/video/comment/replies | standard (1cr) |
| List YouTube video comments | /v1/youtube/video/comments | standard (1cr) |
| Get a YouTube video's subtitle files | /v1/youtube/video/subtitles | standard (1cr) |
| Get a YouTube video's thumbnail files | /v1/youtube/video/thumbnails | standard (1cr) |
| Get YouTube video transcript | /v1/youtube/video/transcript | standard (3cr) |
| Get trending YouTube videos | /v1/youtube/videos/trending | standard (1-6cr)metered |
| Batch get YouTube channel details (up to 1000) | /v1/youtube/channels | advanced (5-100cr)metered |
| Get trending YouTube shorts | /v1/youtube/shorts/trending | advanced (5-15cr)metered |
| Get a YouTube video's audio file streams | /v1/youtube/video/audio | advanced (5cr) |
| Get a YouTube video's video file streams | /v1/youtube/video/files | advanced (5cr) |
| Batch get YouTube video details (up to 1000) | /v1/youtube/videos | advanced (5-100cr)metered |
| Get a YouTube channel's contact email and country. Try the 1-credit youtube/channel first: it already carries the email for some channels, and you are charged here only when an address is returned | /v1/youtube/channel/about | premium (25cr) |
| Detect sponsors of a YouTube video | /v1/youtube/video/sponsors | premium (10cr) |
What should I know about YouTube data?
- Everything is
GETwith query parameters except the three batch endpoints (videos,channels,transcripts), which take aPOSTJSON body - Authentication via
x-api-keyheader - Responses follow the unified SocialCrawl schema
- Channel-scoped endpoints take
channelIdorhandle; video-scoped endpoints take the videourl; playlist endpoints takeplaylist_id - Pagination is
continuationTokenon the channel, search, comments, and hashtag endpoints, andcursoronplaylist,playlist/items,videos/trending, andsearch/advanced. Pass back whatever the previous response returned rather than assuming one name hlonchannel,video, and the two id-batch endpoints sets the localisation language of the returned metadata
Official YouTube Resources
- YouTube Data API v3: Official Google developer documentation
- YouTube Analytics API: Channel and video analytics
