YouTube Scraper (Videos, Comments, Transcripts) avatar

YouTube Scraper (Videos, Comments, Transcripts)

Pricing

from $8.00 / 1,000 results

Go to Apify Store
YouTube Scraper (Videos, Comments, Transcripts)

YouTube Scraper (Videos, Comments, Transcripts)

Scrape YouTube without an API key: video metadata, comments, and transcripts/captions by video URL, video ID, or keyword search. Uses YouTube's InnerTube endpoints. Export JSON/CSV/Excel.

Pricing

from $8.00 / 1,000 results

Rating

0.0

(0)

Developer

Shahryar

Shahryar

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

YouTube Scraper – Videos, Comments & Transcripts (No API Key)

YouTube Scraper extracts structured data from YouTube without an API key or login: video metadata, comments (with replies), and transcripts/captions — by video URL, video ID, or keyword search. Export to JSON, CSV, or Excel.

This is a no-API-key YouTube comments API, YouTube transcript scraper, and video-metadata scraper in one Actor. Built for content researchers, marketers, data teams, and creators who need YouTube data at scale without the official Data API's quota limits.

What it does

  • 🎬 Video metadata – title, description, channel name/ID/URL, view count, approximate like count, publish/upload date, duration, category, tags/keywords, thumbnails, and the list of available caption languages.
  • 💬 Comments – author, text, like count, reply count, relative published time, pinned/hearted flags, and an avatar URL. Optionally expand reply threads.
  • 📝 Transcripts – full transcript text plus timestamped segments, for manual or auto-generated captions, in your preferred language. Best-effort (see FAQ).
  • 🔎 Keyword search – run a YouTube video search and automatically enrich every matching video.
  • 🌍 Language control – pick the caption language and prefer human captions over auto-generated ones.
  • 📤 Export anywhere – download the dataset as JSON, CSV, or Excel, or pull it via the Apify API.

Why this scraper

  • No API key, no login, no quota. Uses YouTube's internal InnerTube endpoints (the same JSON APIs the website calls), reading the live client config from the watch page so the client version is never stale.
  • Honest transcripts. Captions are gated by YouTube; this Actor uses the most reliable path available (InnerTube get_transcript via the iOS client, with a timedtext fallback) and is transparent about when a transcript can't be obtained.
  • Built for reliability. Residential proxy by default, fresh proxy session per video, retries with jitter, and resumable state so a restarted run does not refetch finished videos.
  • One Actor, four data types. Every record carries a type field (video, comment, transcript, searchResult) so you can split the dataset cleanly.
  • Pairs with our other scrapers for social/video data (TikTok, Instagram, Reddit, and more) when you need cross-platform coverage.

How it works (and why it's reliable)

  1. Seed – fetches the watch page once per video and extracts the live INNERTUBE config plus the initial comments token.

  2. Metadata – read straight from the player response (no extra request).

  3. Transcript – resolves the caption track list (language + manual/auto) from the mobile player response, then fetches the text in two stages:

    • Primary: the InnerTube get_transcript (transcript-panel) endpoint, called with the iOS mobile client. The params is a base64-protobuf built from the video ID + chosen track; this endpoint still returns segment text where the plain caption URL does not.
    • Fallback: the timedtext caption baseUrl (fmt=json3). The desktop/web client returns empty caption bodies (exp=xpe / PoToken gate), so mobile clients are used on purpose, but even mobile caption URLs can be gated on some IPs.

    Transcripts are therefore best-effort: when both paths are gated for a given video/IP, no transcript item is emitted (the video and comments are unaffected). A residential proxy materially improves the hit rate.

  4. Comments – paginates the InnerTube next endpoint, joining the thread structure with the frameworkUpdates entity payloads to recover the real text/author/likes.

⚠️ Use a residential proxy. YouTube rate-limits datacenter IPs quickly (HTTP 429s and empty responses), especially for comment pagination. The default proxy group is RESIDENTIAL for this reason — and residential bandwidth is the main cost driver of a run.

Example input

{
"videoUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
"searchQueries": ["lofi hip hop"],
"maxResultsPerSearch": 25,
"scrapeVideoMetadata": true,
"scrapeTranscript": true,
"scrapeComments": true,
"maxComments": 100,
"includeCommentReplies": false,
"commentsSortBy": "top",
"language": "en",
"preferManualCaptions": true,
"emitSearchResults": false,
"proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}

Example output

Each item carries a type field so you can split the dataset by record type. A video that is private, members-only, age-restricted, region-blocked, or not playable is emitted as a type: "skipped" item (with a reason) instead of crashing the run.

Video (type: "video")

{
"type": "video",
"videoId": "dQw4w9WgXcQ",
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"title": "Rick Astley - Never Gonna Give You Up (Official Music Video)",
"description": "The official video for \"Never Gonna Give You Up\" by Rick Astley...",
"channelName": "Rick Astley",
"channelId": "UCuAXFkgsw1L7xaCfnd5JJOw",
"channelUrl": "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw",
"viewCount": 1600000000,
"likeCount": 17000000,
"publishDate": "2009-10-25",
"uploadDate": "2009-10-25",
"durationSeconds": 212,
"category": "Music",
"keywords": ["rick astley", "never gonna give you up"],
"isLiveContent": false,
"isFamilySafe": true,
"thumbnails": [{ "url": "https://i.ytimg.com/...", "width": 1280, "height": 720 }],
"availableCaptionLanguages": [{ "languageCode": "en", "name": "English", "isAutoGenerated": false }],
"commentCountApprox": 2200000,
"foundViaQuery": null,
"scrapedAt": "2026-06-26T10:00:00.000Z"
}

Transcript (type: "transcript")

{
"type": "transcript",
"videoId": "dQw4w9WgXcQ",
"language": "en",
"isAutoGenerated": false,
"trackName": "English",
"fullText": "We're no strangers to love ...",
"segments": [{ "start": 18.5, "dur": 3.2, "text": "We're no strangers to love" }],
"scrapedAt": "2026-06-26T10:00:00.000Z"
}

Comment (type: "comment")

{
"type": "comment",
"videoId": "dQw4w9WgXcQ",
"commentId": "UgxKREWxIgDrw8w2e_Z4AaABAg",
"text": "Still a banger in 2026.",
"authorName": "@someuser",
"authorChannelId": "UCabc...",
"authorChannelUrl": "https://www.youtube.com/channel/UCabc...",
"authorThumbnail": "https://yt3.ggpht.com/...",
"likeCount": 1200,
"replyCount": 8,
"publishedTimeText": "3 weeks ago",
"isPinned": false,
"isHearted": false,
"isReply": false,
"parentCommentId": null,
"scrapedAt": "2026-06-26T10:00:00.000Z"
}

Search result (type: "searchResult", only when Also emit raw search results is enabled)

{
"type": "searchResult",
"query": "lofi hip hop",
"videoId": "jfKfPfyJRdk",
"url": "https://www.youtube.com/watch?v=jfKfPfyJRdk",
"title": "lofi hip hop radio",
"channelName": "Lofi Girl",
"channelId": "UCSJ4gkVC6NrvII8umztf0Ow",
"viewCountText": "Streaming",
"publishedTimeText": null,
"lengthText": null,
"thumbnails": [{ "url": "https://i.ytimg.com/...", "width": 360, "height": 202 }],
"scrapedAt": "2026-06-26T10:00:00.000Z"
}

Output fields

Video (type: "video")

FieldTypeDescription
typestringAlways "video".
videoIdstring11-character video ID.
urlstringCanonical watch URL.
titlestringVideo title.
descriptionstringFull description text.
channelNamestringChannel (author) name.
channelIdstringChannel ID.
channelUrlstringChannel URL.
viewCountintegerTotal views (nullable).
likeCountintegerApproximate like count from the watch UI (nullable; YouTube does not expose an exact number).
publishDatestringPublish date from microformat (nullable).
uploadDatestringUpload date from microformat (nullable).
durationSecondsintegerDuration in seconds (nullable).
categorystringVideo category (nullable).
keywordsarrayTags array (may be empty).
isLiveContentbooleanWhether the video is/was live (nullable).
isFamilySafebooleanFamily-safe flag (nullable).
thumbnailsarrayArray of { url, width, height }.
availableCaptionLanguagesarrayArray of { languageCode, name, isAutoGenerated }.
commentCountApproxintegerApproximate comment count from the header (nullable).
foundViaQuerystringThe search query that surfaced this video (only present for videos discovered via searchQueries).
scrapedAtstringISO 8601 timestamp.

Transcript (type: "transcript")

FieldTypeDescription
typestringAlways "transcript".
videoIdstringVideo ID.
languagestringCaption language code (nullable).
isAutoGeneratedbooleantrue for auto (ASR) captions.
trackNamestringHuman-readable track name (nullable).
fullTextstringAll segments joined into one string.
segmentsarrayArray of { start, dur, text } (seconds as floats; start/dur may be null).
scrapedAtstringISO 8601 timestamp.

Comment (type: "comment")

FieldTypeDescription
typestringAlways "comment".
videoIdstringVideo the comment belongs to.
commentIdstringComment ID.
textstringComment body.
authorNamestringAuthor handle / display name.
authorChannelIdstringAuthor channel ID (nullable).
authorChannelUrlstringAuthor channel URL (nullable).
authorThumbnailstringAuthor avatar URL (nullable).
likeCountintegerLike count (defaults to 0 when not shown).
replyCountintegerReply count (defaults to 0).
publishedTimeTextstringRelative time string (e.g. "3 weeks ago"); YouTube does not expose absolute comment dates.
isPinnedbooleanWhether the comment is pinned.
isHeartedbooleanWhether the creator hearted it.
isReplybooleantrue for replies.
parentCommentIdstringParent comment ID (null for top-level).
scrapedAtstringISO 8601 timestamp.

Search result (type: "searchResult")

FieldTypeDescription
typestringAlways "searchResult".
querystringThe search query that matched.
videoIdstringVideo ID.
urlstringWatch URL.
titlestringVideo title.
channelNamestringChannel name (nullable).
channelIdstringChannel ID (nullable).
viewCountTextstringView-count display string from the search card (nullable).
publishedTimeTextstringRelative publish-time display string (nullable).
lengthTextstringDuration display string (nullable).
thumbnailsarrayArray of { url, width, height }.
scrapedAtstringISO 8601 timestamp.

Skipped (type: "skipped")

FieldTypeDescription
typestringAlways "skipped".
videoIdstringVideo ID that could not be scraped.
urlstringWatch URL.
reasonstringWhy it was skipped (e.g. LOGIN_REQUIRED, AGE_VERIFICATION_REQUIRED, no_video_details, watch_fetch_failed: ...).
scrapedAtstringISO 8601 timestamp.

Input reference

FieldTypeDefaultDescription
videoUrlsarrayYouTube watch URLs (watch?v=, youtu.be/, /shorts/, /embed/, /live/). Normalized to the 11-char ID.
videoIdsarrayRaw 11-character video IDs.
searchQueriesarrayKeyword search strings (videos only); matches are enriched like direct inputs.
maxResultsPerSearchinteger50Max videos per search query (pagination stops once reached).
scrapeVideoMetadatabooleantrueEmit type: "video" items.
scrapeTranscriptbooleantrueFetch transcript/captions (best-effort).
scrapeCommentsbooleanfalseFetch comments (slowest, most rate-limited path).
maxCommentsinteger100Max top-level comments per video; 0 = unlimited.
includeCommentRepliesbooleanfalseAlso expand reply threads.
commentsSortBystringtop"top" or "newest".
languagestringenPreferred caption language code; also sets the InnerTube hl locale.
preferManualCaptionsbooleantruePrefer human captions over auto-generated.
emitSearchResultsbooleanfalseAlso push raw type: "searchResult" items for searches.
proxyConfigurationobjectRESIDENTIALApify proxy; RESIDENTIAL strongly recommended (and the default).

Common use cases

  • Transcript mining – pull YouTube transcripts for summarization, search, or LLM/RAG pipelines.
  • Comment & sentiment analysis – export top or newest comments (and replies) as a YouTube comments API for NLP and analysis.
  • Channel & topic research – search a keyword and collect metadata across many videos at once.
  • Content monitoring – track view counts, approximate likes, and comment volume over time.
  • Competitor & market research – build datasets from competitor channels and export to JSON/CSV/Excel.

FAQ

Do I need a YouTube/Google API key? No. This YouTube scraper uses YouTube's internal InnerTube endpoints — no API key, no OAuth, no quota.

Why are some transcripts missing? Transcripts are best-effort. Not every video has captions, and some only have auto-generated ones. YouTube also gates caption text behind PoToken/IP checks: the Actor first tries the InnerTube get_transcript panel endpoint via the iOS client (which still returns text on mobile clients) and falls back to the timedtext caption URL, but on a gated video/IP combination both can come back empty — in that case the video and comments are still scraped, just without a transcript. A residential proxy improves the YouTube transcript hit rate.

Why are comments slow, and why do they need a proxy? Comments are the slowest, most rate-limited path: the Actor paginates the InnerTube next endpoint one page at a time with jitter to stay under YouTube's limits, so a video with many comments takes proportionally longer. Datacenter IPs get 429s and empty responses quickly, so a residential proxy is strongly recommended when scraping comments at volume. Comments are off by default for this reason.

Why do I need a residential proxy, and what does it cost? Datacenter IPs get rate-limited (429s) and served empty responses, especially during comment pagination, so the default proxy group is RESIDENTIAL. Residential proxy bandwidth is the main cost driver of a run — fetching watch pages, comments, and transcripts all consume residential traffic — so scope your maxComments and maxResultsPerSearch to control spend.

Which languages are supported? Any language YouTube has a caption track for. Set language to a language code (e.g. en, es, de, fr, pt, hi, ja) to pick the caption track and the InnerTube hl locale; if that exact track is missing, the scraper falls back to another track or an auto-generated one. preferManualCaptions controls whether human captions win over ASR.

How are limits and pagination handled? maxResultsPerSearch caps videos per search query, and maxComments caps top-level comments per video (0 = unlimited). Search and comments paginate automatically until the limit is hit or YouTube stops returning a continuation. Runs are resumable: a restarted run skips videos it already finished.

What export formats are available? The dataset can be exported to JSON, CSV, or Excel (also XML, JSONL, RSS, or HTML table) from the Apify Console, or fetched programmatically via the Apify API.


This YouTube scraper pairs well with our other social and video scrapers (TikTok, Instagram, Reddit, and more) when you need cross-platform data.