SocialCrawl

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
curl "https://www.socialcrawl.dev/v1/youtube/channel?handle=MrBeast" \
  -H "x-api-key: YOUR_API_KEY"

2. Fetch their content

cURL
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 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 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.

cURL
# 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) 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.

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.

cURL
# 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 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.

cURL
# 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:

  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
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.

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/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
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
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 callCarries post.ext.channel_id?
search?type=videosYes, on every result
search/advancedYes, on every result, no includeExtras needed
search?type=shortsNo, 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
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.

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 (1-7cr)metered
List a YouTube channel's playlists/v1/youtube/channel/playlistsstandard (1cr)
List YouTube channel shorts/v1/youtube/channel/shortsstandard (1-2cr)metered
List YouTube channel videos/v1/youtube/channel/videosstandard (1-2cr)metered
Get YouTube community post/v1/youtube/community-poststandard (1cr)
Get YouTube playlist/v1/youtube/playliststandard (1-11cr)metered
List the videos in a YouTube playlist/v1/youtube/playlist/itemsstandard (1-11cr)metered
YouTube profile, recent posts, and computed analytics in one call./v1/youtube/profile/fullstandard (5cr)
Search YouTube/v1/youtube/searchstandard (1-11cr)metered
Advanced YouTube video search/v1/youtube/search/advancedstandard (1-11cr)metered
Search YouTube by hashtag/v1/youtube/search/hashtagstandard (1-11cr)metered
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 (3-300cr)metered
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 (1-6cr)metered
Batch get YouTube channel details (up to 1000)/v1/youtube/channelsadvanced (5-100cr)metered
Get trending YouTube shorts/v1/youtube/shorts/trendingadvanced (5-15cr)metered
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
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/aboutpremium (25cr)
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