SocialCrawl

YouTube

YouTube channels, videos, comments, shorts, playlists, community posts, transcripts, media files, and search through one unified API

YouTube

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: sc_your_api_key_here"

2. Fetch their content

curl "https://www.socialcrawl.dev/v1/youtube/channel/videos?handle=MrBeast" \
  -H "x-api-key: sc_your_api_key_here"

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 wantEndpoint
The account snapshotGET /v1/youtube/channel
Regular uploadsGET /v1/youtube/channel/videos
ShortsGET /v1/youtube/channel/shorts
Live and past streamsGET /v1/youtube/channel/lives
PlaylistsGET /v1/youtube/channel/playlists
Text and image postsGET /v1/youtube/channel/community-posts

All five channel-scoped endpoints take either channelId or handle — one is required — and all cost 1 credit. channel additionally accepts a url. 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: sc_your_api_key_here"

# Uploads with engagement counts attached
curl "https://www.socialcrawl.dev/v1/youtube/channel/videos?handle=MrBeast&includeExtras=true&sort=popular" \
  -H "x-api-key: sc_your_api_key_here"

GET /v1/youtube/profile/full (5cr) collapses the first two rows into one call: the channel, its recent videos, and computed metrics — average engagement rate, 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 — with uploadDate, sortBy, type, duration, and region filters.
  • GET /v1/youtube/search/advanced (1cr) returns videos only, but with the full filter set: published_after / published_before windows, license, category, event_type, video_caption, video_definition, video_dimension, video_embeddable, topic_id, location with location_radius, safe_search, and more. Reach for it when a plain keyword search is too blunt, and for search when you need channels or playlists back too.

search/advanced is the one metered endpoint here. The base page is 1 credit; includeExtras=true adds a flat 5 credits to hydrate the page with view, like, and comment counts, because that hydration 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 — 1cr or 6cr, nothing in between.

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: sc_your_api_key_here"

# 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: sc_your_api_key_here"

One video, and everything hanging off it

  • GET /v1/youtube/video (1cr) — the complete record from a video url: 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, and max_results narrow it.
  • GET /v1/youtube/video/comment/replies (1cr) — one thread opened up. It takes the continuationToken that video/comments returned 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 a 404 naming 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 than transcript when 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: sc_your_api_key_here"

# 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: sc_your_api_key_here"

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:

  1. Request order=newest — up to 100 comments per credit.
  2. Keep rows where comment.published_at is on or after your cutoff.
  3. 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: sc_your_api_key_here"

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 both return the same videos. The difference is what comes with them: playlist attaches view counts and durations, playlist/items preserves playlist order and fills in when each video was added. Pick by whether you care about the videos or the sequence.

GET /v1/youtube/community-post (1cr) takes a single post url; GET /v1/youtube/channel/community-posts lists them for a whole channel.

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 no parameters at all, so it is one global list rather than a per-country view.

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/video returns. 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/channel returns, subscriber count included (author.followers). Ids that do not resolve are absent from the list rather than returned empty, so join on author.id, never on array position — the response can be shorter than the request. Note that only the singular channel endpoint accepts a handle or URL; the batch takes bare UC… ids and rejects anything else with a 400 before billing.
  • POST /v1/youtube/transcripts — up to 100 video ids, one transcript row each with the caption language it resolved to and an ok or 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: sc_your_api_key_here" \
  -H "content-type: application/json" \
  -d '{"ids":["dQw4w9WgXcQ","9bZkp7q19f0"],"language":"en"}'

Subscriber counts next to search results

Search returns the video, not the creator behind it — YouTube keeps subscriber counts out of its search index, so no search surface on this API carries one and no parameter can add it. Attaching them is a join, and the key is post.ext.channel_id.

The subscriber count itself lives on author.followers, on both GET /v1/youtube/channel (1cr, and cached for 15 minutes, so a repeat lookup of the same channel inside that window is free) and POST /v1/youtube/channels (5cr per 50 ids). For a crawl, collect channel ids across the whole run, deduplicate, then batch: 23 unique channels resolve in one 5-credit call rather than 23 separate ones.

Which surface hands you the join key matters:

Search callCarries post.ext.channel_id?
search?type=videosYes, on every result
search/advancedYes, on every result, no includeExtras needed
search?type=shortsNo — never. Nor post.author.*
Shorts results carry no creator at all. 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 all null on every type=shorts result — measured 0 of 98 items across three keywords, and includeExtras=true does not change it. Recover the creator by feeding the post.id values to POST /v1/youtube/videos, which returns post.ext.channel_id for all of them at 5 credits per 50.

So a page of 25 Shorts costs 1cr to search, 5cr to resolve the 25 videos to 23 unique channels, and 5cr to resolve those channels to subscriber counts — 11 credits for a fully attributed page. The same page of regular videos skips the middle step: 6 credits.

# 1. Regular videos already carry the channel id
curl "https://www.socialcrawl.dev/v1/youtube/search?query=iphone17&type=videos" \
  -H "x-api-key: sc_your_api_key_here"

# 2. Shorts don't — resolve post.id → channel id first
curl -X POST "https://www.socialcrawl.dev/v1/youtube/videos" \
  -H "x-api-key: sc_your_api_key_here" \
  -H "content-type: application/json" \
  -d '{"ids":["AeBZjMXIoa4","IbDFupquJf4"]}'

# 3. Either way, deduplicate the channel ids and resolve them in one call
curl -X POST "https://www.socialcrawl.dev/v1/youtube/channels" \
  -H "x-api-key: sc_your_api_key_here" \
  -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?

28 endpoints available.

EndpointPathCredit Tier
Get YouTube channel info/v1/youtube/channelstandard (1cr)
List a YouTube channel's community posts/v1/youtube/channel/community-postsstandard (1cr)
List a YouTube channel's live streams/v1/youtube/channel/livesstandard (1cr)
List a YouTube channel's playlists/v1/youtube/channel/playlistsstandard (1cr)
List YouTube channel shorts/v1/youtube/channel/shortsstandard (1cr)
List YouTube channel videos/v1/youtube/channel/videosstandard (1cr)
Get YouTube community post/v1/youtube/community-poststandard (1cr)
Get YouTube playlist/v1/youtube/playliststandard (1cr)
List the videos in a YouTube playlist/v1/youtube/playlist/itemsstandard (1cr)
YouTube profile, recent posts, and computed analytics in one call./v1/youtube/profile/fullstandard (5cr)
Search YouTube/v1/youtube/searchstandard (1cr)
Advanced YouTube video search/v1/youtube/search/advancedstandard (1-6cr)metered
Search YouTube by hashtag/v1/youtube/search/hashtagstandard (1cr)
Get YouTube search suggestions/v1/youtube/search/suggestionsstandard (1cr)
Up to 100 YouTube video ids → one transcript per row, failed ids refunded./v1/youtube/transcriptsstandard (3cr)
Get YouTube video details/v1/youtube/videostandard (1cr)
List YouTube comment replies/v1/youtube/video/comment/repliesstandard (1cr)
List YouTube video comments/v1/youtube/video/commentsstandard (1cr)
Get a YouTube video's subtitle files/v1/youtube/video/subtitlesstandard (1cr)
Get a YouTube video's thumbnail files/v1/youtube/video/thumbnailsstandard (1cr)
Get YouTube video transcript/v1/youtube/video/transcriptstandard (3cr)
Get trending YouTube videos/v1/youtube/videos/trendingstandard (1cr)
Batch get YouTube channel details (up to 1000)/v1/youtube/channelsadvanced (5-100cr)metered
Get trending YouTube shorts/v1/youtube/shorts/trendingadvanced (5cr)
Get a YouTube video's audio file streams/v1/youtube/video/audioadvanced (5cr)
Get a YouTube video's video file streams/v1/youtube/video/filesadvanced (5cr)
Batch get YouTube video details (up to 1000)/v1/youtube/videosadvanced (5-100cr)metered
Detect sponsors of a YouTube video/v1/youtube/video/sponsorspremium (10cr)

What should I know about YouTube data?

  • Everything is GET with query parameters except the three batch endpoints (videos, channels, transcripts), which take a POST JSON body
  • Authentication via x-api-key header
  • Responses follow the unified SocialCrawl schema
  • Channel-scoped endpoints take channelId or handle; video-scoped endpoints take the video url; playlist endpoints take playlist_id
  • Pagination is continuationToken on the channel, search, comments, and hashtag endpoints, and cursor on playlist, playlist/items, videos/trending, and search/advanced. Pass back whatever the previous response returned rather than assuming one name
  • hl on channel, video, and the two id-batch endpoints sets the localisation language of the returned metadata

Official YouTube Resources