Youtube Scraper Pro
Pricing
from $2.00 / 1,000 video results
Youtube Scraper Pro
Full‑fidelity YouTube data extractor for videos, Shorts, live streams, and channels. Built on Apify + Puppeteer for reliable, scalable web scraping that returns complete metadata, engagement stats, caption tracks for transcripts, hashtags/keywords, description links, and channel insights — fast.
Pricing
from $2.00 / 1,000 video results
Rating
0.0
(0)
Developer
Delowar Munna
Maintained by CommunityActor stats
2
Bookmarked
34
Total users
0
Monthly active users
2 days ago
Last modified
Categories
Share
YouTube Scraper Pro (Apify Actor)
Analytics-ready YouTube data for videos, Shorts, live streams, and channels. Built on the official YouTube Data API v3 with HTTP + Innertube fallbacks — no cookies, no login, no residential proxy required — returning engagement metrics, SEO signals, parsed description links, channel intelligence, and result provenance.

Transcripts: this actor can attach captions per video — enable
includeTranscriptto fill asubtitlesarray (SRT, VTT, plain text, or JSON — one or more). For standalone / bulk transcript jobs, our dedicated YouTube Transcript Scraper is purpose-built.
At a Glance
- Official-API sourced: YouTube Data API v3 for core fields, with HTTP + Innertube fallbacks — no cookies, no logged-in session, no residential proxy
- Scrape by keywords, channel handles (e.g.
@mkbhd), channel IDs, playlists, or direct video URLs - Returns: title, description, duration, publish date, views, likes, comment count, category, media flags (HD/4K/HDR), hashtags, keywords, parsed description links, monetization status, and rich channel data
- Provenance on every row: which query produced it, its order, and when it was collected — unique to this actor
- Spreadsheet-friendly: flat camelCase keys plus a nested
channelobject; import straight into Google Sheets, Excel, or a database - Spend control: cap the whole run with
maxItems
Best for: content research, SEO, competitive intelligence, trend analysis, brand monitoring, influencer discovery, and analytics-ready ETL feeds.
How it works
Each video is resolved through a tiered pipeline; every tier only handles what the previous one could not, so most videos never touch a browser:
| Tier | Role | Cost |
|---|---|---|
| HTTP extraction | Fetches raw HTML + parses embedded JSON (ytInitialData, ytInitialPlayerResponse) | ~1s/video, no browser |
| YouTube Data API v3 | Batch core fields (views, likes, duration, category, keywords) | 1 quota unit per 50 videos |
| Innertube | /youtubei/v1/player fallback when HTTP is soft-blocked | no browser |
| TikHub | Hosted-API fallback for videos the above could not resolve (e.g. datacenter-IP blocks) | paid, only when needed |
| Puppeteer (browser) | Last-resort DOM extraction; skipped entirely when nothing is left | rare |
No residential proxy is required for normal use. The actor works reliably from datacenter IPs; the TikHub tier absorbs the cases where a raw HTTP fetch is blocked.
Key Features
- API-first discovery (fast): keyword & #hashtag search via TikHub; channel / playlist / seed-video expansion via the YouTube Data API v3 — no browser for discovery. A browser is only a rare last-resort for videos no API tier can resolve.
- One discovery field: keywords, #hashtags, channels (URL /
@handle/UC…), playlists (URL /PL…), or a seed video (expands to its owning channel). Plus a separate direct-video field. - Content coverage: standard videos, Shorts (duration-detected), live/live-replay — filter with
contentType - Filters & sorting:
contentType,videoDuration,titleFilter,uploadDate/date range, andsortBy(relevance / newest / most-viewed), applied to discovered results - Localization: 37 countries (
regionCode) and 20 languages (language) - SEO signals: hashtags, keywords/tags, parsed outbound description links
- Channel intelligence: id, name, handle, URL, numeric subscriber count, totals, country, profile image, join date, description
- Monetization detection:
isMonetized(+commentsAllowed,isRatingsAllowed) when reachable - Detected language:
detectedLanguage(API hint + trigram detection) - Optional subtitles:
includeTranscriptfills asubtitlesarray (SRT/VTT/txt/JSON, one or more, each + a key-value-store file link) via TikHub captions (off by default; billed only when delivered) - Result provenance:
source,order,collectedAton every record - Spend cap:
maxItemsbounds the total results saved across the whole run
Quick Start (Apify)
- Create an Actor task and paste one of the JSON inputs below.
- Set
maxItemsif you want to cap total spend for the run. - Run. Export JSON/CSV/Excel to your datastore, Google Sheets, or S3.
Input Schema
The input form is organized into four collapsible sections:
- 1. What to scrape — the combined discovery field, direct video URLs/IDs, and result limits
- 2. Filters & Sorting — content type, duration, title filter, sort, dates, trending
- 3. Advanced — localization and output format
- 4. Transcript — optional caption extraction
Input Parameters
| # | Field | Key | Type | Required | Default | Description |
|---|---|---|---|---|---|---|
| 1 | Search, Channels, Playlists & Discovery | searchQueries | Array | No | [] | Discovery sources, auto-detected: a keyword, a #hashtag, a channel (URL / @handle / /channel/UC… / /c/… / /user/… / bare UC…), a playlist (URL or bare PL…/UU…), or a video (URL/ID — treated as a seed: its owning channel is scraped). Each source capped by maxResultsPerQuery |
| 2 | YouTube URLs or IDs | startUrls | Array | No | [] | Direct videos — one record per entry, for that video only (no expansion, exempt from filters). Full URLs (watch?v=…, youtu.be/…, /shorts/…) or bare 11-char IDs. Non-video entries are skipped |
| 3 | Max videos per source | maxResultsPerQuery | integer | No | 10 | Caps each discovery source (keyword/hashtag/channel/playlist/seed) individually. Min 1. Doesn't apply to YouTube URLs/IDs (one video each) |
| 4 | Max results (whole run) | maxItems | integer | No | 0 | Global spend cap — total results saved across the run, applied after filter + sort. 0 = no global limit |
| 5 | Content type | contentType | string | No | "all" | all / videos / shorts / live. Shorts detected by duration (≤ 60s); live from broadcast status. Discovered results only |
| 6 | Duration | videoDuration | string | No | "all" | all / short (<4m) / medium (4–20m) / long (>20m). Discovered results only |
| 7 | Sort results by | sortBy | string | No | "relevance" | relevance (discovery order) / date (newest) / views (most viewed). Sorts the discovered set before the cap |
| 8 | Upload date filter | uploadDate | string | No | "any" | any / hour / today / week / month / year. Applies to all discovered sources |
| 9 | Title filter | titleFilter | string | No | "" | Comma-separated keywords; keep results whose title contains at least one (OR, case-insensitive) |
| 10 | Include trending videos | getTrending | boolean | No | false | Also add the Country's trending videos as a source (official Data API; requires an API key) |
| 11 | From Date | dateFrom | string | No | "" | Publish-date lower bound (YYYY-MM-DD). Applies to all discovered sources |
| 12 | To Date | dateTo | string | No | "" | Publish-date upper bound (YYYY-MM-DD). Applies to all discovered sources |
| 13 | Country | regionCode | string | No | "US" | ISO-3166-1 alpha-2. 37 options (US, GB, DE, IN, JP, KR, ID, BR, NG, …) |
| 14 | Language | language | string | No | "en" | IETF BCP-47. 20 options (en, es, de, ja, ko, hi, id, ar, …) |
| 15 | Output format | outputMode | string | No | "rich" | rich (nested JSON) or analyticsFlat (nested objects flattened into channel_name, features_isHD, … and arrays joined — spreadsheet-friendly) |
| 16 | Include Transcript | includeTranscript | boolean | No | false | Fill the subtitles array via TikHub captions. Adds ~1–2s/video; ~60–80% of videos have captions. Billed per delivered subtitle |
| 17 | Subtitle formats | subtitleFormats | Array | No | ["srt"] | Multi-select: any of srt, vtt (timestamped), txt (plain text), json ({start,dur,text} segments). Each selected format is added to the subtitles entry |
| 18 | Transcript Language | transcriptLanguage | string | No | "" | Preferred caption language; empty = auto (first available). Only used when Include Transcript is on |
Filters apply to discovered results only — videos listed directly in YouTube URLs or IDs are always returned as-is (exempt from
contentType/videoDuration/titleFilter/date).
Keyword & hashtag search requires a TikHub key; channel/playlist/seed expansion and metadata require the YouTube API key. Both are set as Apify secrets.
Tip: start with a small
maxResultsPerQuery(and/or amaxItems) to validate your setup, then scale up.
Input Example — 01: Search with date filtering and a spend cap
{"searchQueries": ["AI tools", "machine learning", "#openai"],"maxResultsPerQuery": 20,"maxItems": 50,"contentType": "videos","sortBy": "views","uploadDate": "month","videoDuration": "medium","regionCode": "US","language": "en"}
Input Example — 02: Direct video URLs and IDs
{"startUrls": ["https://www.youtube.com/watch?v=7Sx0o-41r2k","https://youtu.be/5oAnKSCP4do","QJBP2uy8LcU"]}
Input Example — 03: Channels, playlists, and a seed video (all in Discovery)
{"searchQueries": ["@MKBHD","UCXuqSBlHAE6Xw-yeJA0Tunw","https://www.youtube.com/playlist?list=PLBCF2DAC6FFB574DE","https://www.youtube.com/watch?v=dQw4w9WgXcQ"],"contentType": "all","maxResultsPerQuery": 25,"regionCode": "US","language": "en"}
The last entry is a video URL — in the Discovery field it's a seed: the channel that owns it is scraped for up to
maxResultsPerQueryvideos. The same value in the YouTube URLs or IDs field would instead return only that one video.
Input Example — 04: With subtitles
{"searchQueries": ["langchain tutorial"],"maxResultsPerQuery": 10,"includeTranscript": true,"subtitleFormats": ["srt", "json"],"transcriptLanguage": "en"}
What you pay
This actor uses Apify's pay-per-event pricing. The live rates are shown on the Pricing tab of the actor page — this README deliberately does not quote figures, because the amounts are set on the platform and can change.
You are charged for:
| Event | Fires when | Notes |
|---|---|---|
| Result | A video record is saved to the dataset | The main charge. One per video returned. |
| Discovery (search) | A discovery source (keyword, hashtag, channel, playlist, or seed video) returns at least one result | A discovery that returns zero results is not charged. Direct video URLs never incur a discovery charge — you pay only for the result. |
| Transcript | A transcript is actually delivered for a video | Only when includeTranscript is on and captions exist. Videos without captions are not charged. |
Controlling spend:
- Set
maxItemsto cap the total number of results (and therefore the total result charges) for the whole run. - Use
maxResultsPerQueryto cap each individual source. - Leave
includeTranscriptoff unless you need spoken text — it adds a per-delivered-transcript charge. - Error/unavailable rows (see Errors & limitations) are not billed as normal results.
For worked cost examples at the current rates, see the Pricing tab on the actor page.
Output Schema
Each record has 35 top-level fields. Legacy keys (VideoId, PageURL, publishDate) are retained alongside their normalized aliases (id, url, publishedAt) for backward compatibility. Set outputMode: "analyticsFlat" to flatten nested objects into top-level columns for spreadsheets.
Core fields
| # | Field | Type | Description |
|---|---|---|---|
| 1 | type | String | One of video, shorts, live, stream |
| 2 | isShort | Boolean | Convenience mirror of type === "shorts" |
| 3 | VideoId | String | YouTube video ID (legacy key) |
| 4 | id | String | YouTube video ID (camelCase alias of VideoId) |
| 5 | PageURL | String | Canonical watch URL (legacy key) |
| 6 | url | String | Canonical watch URL (camelCase alias of PageURL) |
| 7 | title | String | Video title |
| 8 | thumbnailUrl | String | null | Primary/hero thumbnail URL |
| 9 | publishDate | String | null | Publish date (date, or ISO if a time is known) |
| 10 | publishedAt | String (ISO-8601) | null | Full timestamp when a real time is known; null when only a date is available (never fabricated) |
| 11 | duration | String | null | HH:MM:SS (e.g. 00:22:43) |
| 12 | durationSeconds | Integer | null | Duration in seconds |
| 13 | viewCount | Integer | null | Total views |
| 14 | likeCount | Integer | null | Total likes |
| 15 | commentCount | Integer | null | Public comment count |
| 16 | category | String | null | Video category |
State flags
| # | Field | Type | Description |
|---|---|---|---|
| 17 | isLive | Boolean | Whether the item is/was a live stream |
| 18 | isMembersOnly | Boolean | Members-only gated flag |
| 19 | isPrivate | Boolean | Private/unavailable to public |
| 20 | isFamilySafe | Boolean | null | Family-safe flag if exposed |
| 21 | isMonetized | Boolean | null | Monetization detectable flag |
| 22 | isRatingsAllowed | Boolean | null | Whether likes/dislikes are enabled |
| 23 | commentsAllowed | Boolean | null | Whether comments are enabled |
Content & media
| # | Field | Type | Description |
|---|---|---|---|
| 24 | description | String | null | Creator-written description |
| 25 | descriptionLinks | Array | Outbound links parsed from the description ({url, text}) |
| 26 | subtitles | Array | Captions — empty [] unless includeTranscript is on and captions exist. See shape below |
| 27 | keywords | Array | Tags/keywords |
| 28 | hashtags | Array | Hashtags from title/description |
| 29 | features | Object | Media flags: isHD, is4K, isHDR, isVR180, is360 (each Boolean | null) |
subtitles entry: one object per caption track, carrying type, language, and — for each selected subtitleFormats — an inline <fmt> value plus a <fmt>Url link to the file in the run's key-value store (signed URL on the platform). <fmt> is srt/vtt/txt (String) or json (Array of {start, dur, text} in seconds). type is auto_generated (the TikHub captions list does not distinguish auto vs manual, so this is best-effort). Example with subtitleFormats: ["srt","json"]:
"subtitles": [{"type": "auto_generated", "language": "en","srtUrl": "https://api.apify.com/v2/key-value-stores/<id>/records/subtitles_<vid>_en_auto_generated.srt?signature=…","srt": "1\n00:00:01,360 --> 00:00:03,040\n[♪♪♪]\n\n2\n…","jsonUrl": "https://api.apify.com/v2/key-value-stores/<id>/records/subtitles_<vid>_en_auto_generated.json?signature=…","json": [ { "start": 1.36, "dur": 1.68, "text": "[♪♪♪]" }, … ]}]
Derived analytics
Computed by this actor from the fields above — not source-native YouTube values. null when the required inputs are missing.
| # | Field | Type | Description |
|---|---|---|---|
| 30 | engagementRate | Number | null | (likeCount + commentCount) / viewCount |
| 31 | videoAgeDays | Integer | null | Whole days since publication |
| 32 | viewsPerDay | Integer | null | viewCount / max(videoAgeDays, 1) |
| 33 | detectedLanguage | String | null | 2-letter language code — API audio/default-language hint, else trigram detection over title+description |
Channel & provenance
| # | Field | Type | Description |
|---|---|---|---|
| 34 | channel | Object | Channel metadata (see below) |
| 35 | provenance | Object | order (Integer | null), source (keyword/hashtag/channel/playlist/seed/trending/startUrls), query, collectedAt (ISO-8601) |
channel object: id, name, handle, url, subscriberCount (Integer | null — normalized), subscriberCountText (String | null — the display form "4.42M subscribers" when the video page is read; the raw count as a string, e.g. "201000", on the API-only path), totalViews, totalVideos, country, profileImage, description, createdAt, links.
Channel-level fields (subscriberCount, totalViews, totalVideos, country, description, profileImage, handle, url, createdAt) are populated by a batched channels.list call (one per unique channel per run) when a YouTube API key is configured; without a key most remain null. links is not populated (it requires scraping the channel About page) and is always empty.
Sample output
A real record from a keyword run (searchQueries: ["tesla"], includeTranscript: true, subtitleFormats: ["srt","vtt","txt","json"]). Long fields (srt/vtt/txt/json, description) are truncated here with …; the caption files are also linked in the run's key-value store. On datacenter IPs the DOM-only fields (isMonetized/commentsAllowed/isRatingsAllowed) may be null — see Field availability below.
{"type": "video","isShort": false,"VideoId": "qoh_rrgcUQ4","id": "qoh_rrgcUQ4","PageURL": "https://www.youtube.com/watch?v=qoh_rrgcUQ4","url": "https://www.youtube.com/watch?v=qoh_rrgcUQ4","title": "Tesla's Most Underrated Achievement Just Became Normal","thumbnailUrl": "https://i.ytimg.com/vi/qoh_rrgcUQ4/maxresdefault.jpg","publishDate": "2026-07-27","publishedAt": "2026-07-27T18:51:11Z","duration": "00:40:47","durationSeconds": 2447,"viewCount": 15390,"likeCount": 985,"commentCount": 71,"category": "Science & Technology","isLive": false,"isMembersOnly": false,"isPrivate": false,"isFamilySafe": null,"isMonetized": null,"isRatingsAllowed": null,"commentsAllowed": null,"description": null,"descriptionLinks": [],"subtitles": [{"type": "auto_generated","language": "en","srtUrl": "https://api.apify.com/v2/key-value-stores/<id>/records/subtitles_qoh_rrgcUQ4_en_auto_generated.srt?signature=…","srt": "1\n00:00:00,080 --> 00:00:04,000\nTeslas are now driving coast to coast\n…","vttUrl": "https://api.apify.com/v2/key-value-stores/<id>/records/subtitles_qoh_rrgcUQ4_en_auto_generated.vtt?signature=…","vtt": "WEBVTT\n\n00:00:00.080 --> 00:00:04.000\nTeslas are now driving coast to coast\n…","txtUrl": "https://api.apify.com/v2/key-value-stores/<id>/records/subtitles_qoh_rrgcUQ4_en_auto_generated.txt?signature=…","txt": "Teslas are now driving coast to coast without a single intervention. …","jsonUrl": "https://api.apify.com/v2/key-value-stores/<id>/records/subtitles_qoh_rrgcUQ4_en_auto_generated.json?signature=…","json": [ { "start": 0.08, "dur": 3.92, "text": "Teslas are now driving coast to coast" }, "…" ]}],"keywords": ["tesla", "tsla", "tesla stock", "investing", "…"],"hashtags": [],"features": { "isHD": null, "is4K": null, "isHDR": null, "isVR180": null, "is360": null },"engagementRate": 0.06862,"videoAgeDays": 0,"viewsPerDay": 15390,"detectedLanguage": "en","channel": {"id": "UC4DBLlq1x0AKmip1QJUcbXg","name": "Brighter with Herbert","subscriberCount": 201000,"subscriberCountText": "201000","totalViews": 89815604,"totalVideos": 2516,"country": "US","description": "Interviews about the future (Tesla, SpaceX, Robots and AI) …","profileImage": "https://yt3.ggpht.com/…","createdAt": "2012-10-24","handle": "@brighterwithherbert","url": "https://www.youtube.com/@brighterwithherbert"},"provenance": { "source": "keyword", "query": "tesla", "order": 1, "collectedAt": "2026-07-28T00:26:25.553Z" }}
Field availability & nullability
This actor extracts public data. Not every field is available for every video — a null means "not available for this video", not an error. Plan your downstream models for nullable fields.
| Field(s) | May be null when |
|---|---|
likeCount, commentCount | The creator has hidden likes/comments, or comments are disabled |
isMonetized, isFamilySafe, isRatingsAllowed | The signal is not exposed for that video |
publishedAt | Only a publish date (no time) is available — the field stays null rather than inventing a time |
category | Not exposed in the available metadata |
channel.subscriberCount / subscriberCountText | The channel hides its subscriber count |
channel.totalViews, totalVideos, country, description, profileImage, handle, url, createdAt | No API key configured (these come from a channels.list enrichment call), or the channel hides them |
channel.links | Always empty — requires scraping the channel About page (not part of this actor) |
subtitles | Empty [] unless includeTranscript is on and the video has captions (~60–80% do) |
detectedLanguage | Title/description too short to detect and no API language hint |
| Dislikes | Always unavailable — YouTube no longer exposes dislike counts publicly |
Captions are opt-in via
includeTranscript(→subtitles). For standalone/bulk transcript jobs, use the YouTube Transcript Scraper.
Errors & limitations
- Unavailable videos (private, removed, age-restricted, geo-blocked, members-only) produce a typed error record rather than vanishing silently (see below).
- Date filtering applies to Search Keywords only, not direct URLs.
- Dislikes are never available (YouTube removed public dislike counts).
- Transcripts/captions are opt-in (
includeTranscript→subtitlesarray); for standalone/bulk transcript jobs use the dedicated transcript actor linked above. - Rate limits: the actor throttles itself to respect YouTube; very large jobs should be batched by topic/channel.
Error records
When an input can't be resolved, the dataset gets a typed error row instead of dropping it silently. Error rows are never billed as results and don't count against maxItems. Filter them out with type != "error".
{"type": "error","input": "https://www.youtube.com/watch?v=...","videoId": "...","errorCode": "PRIVATE","errorMessage": "This video is private","retryable": false,"source": "startUrls","collectedAt": "2026-07-25T10:00:00.000Z"}
errorCode is one of PRIVATE, AGE_RESTRICTED, MEMBERS_ONLY, VIDEO_UNAVAILABLE, GEO_BLOCKED, BLOCKED, NETWORK_ERROR, EXTRACTION_FAILED. retryable tells you whether re-running the input might succeed (transient) or never will (permanent).
Run summary
Every run writes a RUN_SUMMARY record to the default key-value store (and logs it): inputs provided, results saved, and a per-code error breakdown — so you can tell "requested vs returned" at a glance without scanning the dataset.
Integrations
Because this runs on the Apify platform, its dataset plugs into the standard Apify integrations with no extra work:
- Export: JSON, CSV, Excel, XML directly from the dataset
- Google Sheets / Airtable / databases: push results via Apify integrations
- Automation: Make, Zapier, and n8n connectors
- Webhooks: trigger downstream workflows on run completion
- API & clients: fetch results via the Apify API, or the JavaScript / Python Apify clients
- MCP / AI agents: the dataset is reachable by AI-agent tooling through the Apify platform
Compared to alternatives
Honest positioning against other YouTube actors on Apify:
| YouTube Scraper Pro (this actor) | Typical high-volume scrapers | Typical low-cost scrapers | |
|---|---|---|---|
| Data source | Official YouTube Data API v3 + HTTP/Innertube/TikHub | Unofficial extraction | Unofficial extraction |
| Cookies / login required | No | Sometimes | Sometimes |
| Result provenance (source/order/time) | Yes | Rarely | Rarely |
| Monetization + parsed description links | Yes | Sometimes | Rarely |
| Single-video URLs | Supported | Varies | Often not allowed |
| Transcripts | Separate transcript actor | Sometimes built in | Rarely |
| Raw throughput (videos/sec) | Competitive, not the leader | Higher on some actors | Varies |
| Price | Mid-market | Often lower | Lowest |
Where we win: official-API sourcing, provenance, monetization/description-link depth, single-video support, and a simple schema. Where others win: raw throughput and rock-bottom price. Choose this actor when you want trustworthy, analytics-ready data over the cheapest-possible bulk dump.
Performance
- HTTP-first: most videos are saved directly over HTTP without launching a browser; the Puppeteer tier is a rare last resort.
- Concurrency: up to 10 parallel requests.
- Memory: default 2 GB (min 1 GB / max 4 GB). Pure-HTTP runs work at 1 GB; the default leaves headroom for the occasional browser fallback.
⏳ Throughput benchmark pending re-measurement. The previously published figure (~7s/video) described an older browser-heavy path and no longer reflects the HTTP-first architecture. A refreshed videos-per-minute benchmark will be added after a fresh Apify run.
Popular Use Cases
- SEO research: surface keywords, tags, hashtags, and linking practices
- Content strategy: analyze formats, titles, and posting cadence
- Competitive intelligence: benchmark creators and track launches
- Market/academic research: study trends by niche, region, or language
- Brand monitoring: find mentions and categorize sentiment downstream
- Influencer discovery: filter by views/engagement within your topics
- Analytics ETL: feed provenance-tagged, normalized rows into a warehouse
FAQ
Where does the data come from? The official YouTube Data API v3 for core fields, with HTTP page extraction and the Innertube API as fallbacks, and a hosted-API tier (TikHub) for videos that datacenter IPs can't reach directly. No cookies, no login, no residential proxy.
Do I need a residential proxy? No. The actor works reliably from datacenter IPs. Residential proxy is not required and not part of the standard input.
How do I control how much I spend?
Set maxItems to cap the total results for the whole run, and maxResultsPerQuery to cap each source. Pricing is per event — see What you pay and the Pricing tab.
What am I charged for? Per result saved, plus a discovery event for search/channel/playlist sources. Direct video URLs incur no discovery charge. See What you pay.
Can I get transcripts or subtitles?
Yes — set includeTranscript: true to fill the subtitles array via TikHub captions (off by default; billed per delivered subtitle). Choose one or more subtitleFormats — srt/vtt (timestamped), txt (plain text), or json ({start,dur,text} segments); each entry includes every selected format inline plus a key-value-store file link. For standalone / bulk transcript jobs, the dedicated YouTube Transcript Scraper is purpose-built.
Can I scrape a whole channel?
Yes — put the channel's @handle, channel ID (UC…), or channel URL into the Discovery field. You can also drop in a video URL/ID there and it's treated as a seed — resolved to the channel that owns it. Use maxResultsPerQuery to limit videos per source.
Can I search by hashtag?
Yes — put a #tag (or a youtube.com/hashtag/<tag> URL) in the Discovery field. It's routed through TikHub search (requires a TikHub key).
Can I target a country or language?
Yes — set regionCode (37 countries) and language (20 codes).
Can I sort or filter results?
Yes — sortBy (relevance / newest / most-viewed), plus contentType, videoDuration, titleFilter, uploadDate, and dateFrom/dateTo. These are applied to the discovered set. Videos listed directly in YouTube URLs or IDs are exempt (always returned).
Can I get trending videos?
Yes — set getTrending: true to also scrape the Country's currently trending videos (via the official Data API chart=mostPopular). Requires a YouTube API key; the count follows maxResultsPerQuery.
Can I filter by date?
Yes — dateFrom and dateTo (YYYY-MM-DD), applied to all discovered sources. (For relative windows, uploadDate is simpler.)
What about Shorts and live videos?
Use contentType (all / videos / shorts / live). Shorts are detected by duration (≤ 60s), live from broadcast status. Every record is tagged with type (video/shorts/live) and isShort/isLive flags. Videos listed directly in YouTube URLs or IDs are always returned regardless of this filter.
Are dislikes available? No — YouTube no longer exposes dislike counts publicly. There is no dislike field.
Why are some fields null?
null means the value isn't public for that video (hidden counts, restricted content, or channel data not fetched). See Field availability & nullability.
How do I import into Google Sheets or Excel?
Export the dataset as CSV/Excel, or push it via the Apify Google Sheets integration. Flat camelCase keys make columns clean; the channel object expands into channel/... columns.
What happens to unavailable videos?
Private, removed, age-restricted, geo-blocked, or members-only videos produce a typed error record (with an errorCode and a retryable flag) instead of vanishing. Error records aren't billed as results and don't count against maxItems. A RUN_SUMMARY in the key-value store gives you the requested-vs-returned totals and a per-code error breakdown.
Best Practices
- Start small: validate with
maxResultsPerQuery: 5–10(and amaxItemscap). - Filter early: set
contentTypeandvideoDuration; useuploadDate/dateFrom/dateToto narrow results. - Bulk processing: paste many entries into Discovery (keywords / channels / playlists / hashtags) or YouTube URLs or IDs (one per line).
- Batch thoughtfully: group by topic/channel.
- Schema-first: build downstream models against the stable keys above; treat nullable fields as nullable.
Compliance
- Intended for legitimate research & business intelligence.
- Collects only public information.
- Uses the official YouTube Data API v3; respects its Terms of Service.
- Respect YouTube's Terms of Service and applicable laws in your jurisdiction.
Changelog
- v3.1 (this release — pending deploy):
- ⚡ API-first discovery: keyword & #hashtag search via TikHub; channel/playlist/seed-video expansion via the YouTube Data API — no browser for discovery (was the main slowdown on datacenter IPs). Browser is now a rare last-resort for videos no API tier can resolve.
- 🧭 Input reorganized to match the sibling video-finder: one combined Discovery field + a Direct URLs field;
contentTypeselect andtitleFilterreplace the per-type toggles/caps; discovery filters/sort applied client-side (fetch → filter → sort → cap). - 🌐
detectedLanguagefield (API hint +franc-mintrigram detection) - 📝 Optional
subtitles(includeTranscript+ multi-selectsubtitleFormats(srt/vtt/txt/json) +transcriptLanguage) via TikHub captions — each entry has inline content + a key-value-store file link; off by default, billed per delivered subtitle (newtranscriptpay-per-event) - 🏷️ Channel enrichment now also fills
handle,url,createdAtfor API-discovered records
- v3.0:
- 🔑 API keys wired as Apify secrets (
@youtube_api_key_scraper_pro, shared@tikhub_api_key) — no hardcoded keys - 🛰️ New TikHub reliability tier between Innertube and the browser: recovers datacenter-blocked videos and avoids browser visits
- 🧮 Global spend cap via
maxItems - 🧱 Normalized output:
id/urlaliases,publishedAt(ISO, null when only a date is known),isShort, numericchannel.subscriberCount+subscriberCountText - 📊 Derived analytics:
engagementRate,videoAgeDays,viewsPerDay - 🧾
analyticsFlatoutput mode for spreadsheet-friendly flat columns - 🧮 Discovery event is not charged when a search/channel returns zero results
- 🧯 Typed error records for failed inputs (never billed) + a
RUN_SUMMARYin the key-value store - 🔤 Sorting (
sortBy) and server-side filters (uploadDate,duration) for search - 🔥 Trending videos input (
getTrending) via the official Data API - 📡 Live-stream control (
includeLiveStreams) + per-content-type caps (maxVideos/maxShorts/maxLiveStreams) - 🏷️ Channel enrichment:
channel.totalViews/totalVideos/country/descriptionfilled via a cachedchannels.listcall;profileImagenow populated from the video page - 🗂️ Input form reorganized (What to scrape / Filters / Advanced); localization expanded to 37 countries and 20 languages
- 🧠 Memory default 4 GB → 2 GB (browser fallback is now rare)
- 📝 Documentation reconciled with the code (30 fields; captions/transcripts pointed to the dedicated actor)
- 🔑 API keys wired as Apify secrets (
- v2.8: 3-tier hybrid extraction (HTTP + API + optimized browser); graceful degradation on datacenter IPs
- v2.7: Removed captions field (required residential proxy, always null on datacenter IPs)
- v2.6: Hybrid YouTube Data API v3 + web scraping architecture; residential proxy made optional
- v2.5: Date-range filtering for search queries; bulk URL upload
- v2.0: Performance tuning, richer channel fields, improved localization
Get Help
- Issues & feature requests → GitHub / Apify support
- Need something custom? Open an issue describing your dataset needs