Youtube Video Details Scraper
Pricing
$19.99/month + usage
Youtube Video Details Scraper
YouTube Video Details Scraper extracts metadata from public YouTube videos, including title, description, channel name, view count, likes, tags, upload date, and more. Ideal for research, SEO, analytics, or automation—just input video URLs and get structured data effortlessly.
Pricing
$19.99/month + usage
Rating
5.0
(4)
Developer
Scraper Engine
Maintained by CommunityActor stats
0
Bookmarked
59
Total users
2
Monthly active users
4 days ago
Last modified
Categories
Share
YouTube Video Details Scraper — Views, Tags and Transcripts
YouTube Video Details Scraper turns a list of public YouTube video URLs into structured JSON rows: title, full description, view count, like count, comment count, duration, publish date, creator tags, category, true maximum resolution, every thumbnail size YouTube publishes, the uploading channel, and a time-aligned transcript built from YouTube's own caption track. One URL in, one typed row out. No Google API key, no OAuth, no login. Paste your URLs on Apify and press Start.
⚠️ What this Actor does not return
Read this before your first run, because two of these are the assumptions people most often bring to a "video details" scraper.
No video or stream URL. The Actor never downloads media and never emits a playable link. Extraction runs with downloads disabled; the format list is read for one purpose only, to compute the true maximum resolution. There is no formats array, no DASH or HLS manifest, no progressive MP4 and no audio URL anywhere in the output. The only media links returned are image URLs — the thumbnail set on thumbnails and the channel avatar on channel.logo.
Transcripts, however, are returned. That is the field this Actor exists for, and it comes back as timed cues rather than a wall of text. Details are in the output section.
Also absent, and absent on purpose rather than shipped as an always-empty column: comment bodies and replies (only YouTube's comment_count total is returned), chapter markers, dislike counts — YouTube removed the public dislike figure in 2021, so no scraper can return it — related-video lists, and any channel contact email. There is no cookie or credential field, so age-restricted videos cannot be unlocked.
What is YouTube Video Details Scraper?
YouTube Video Details Scraper is an Apify Actor that takes public YouTube video URLs and returns one normalized JSON row per video, combining the video's own metadata, the uploading channel's public identity, and the video's caption track as timed transcript cues.
No YouTube account, Google login, Google Cloud project or API key is required — none is used at runtime and there is no field in the input schema to supply one. The only credential involved is your Apify token. It is built for developers assembling video datasets, SEO and content teams researching tags and descriptions at scale, and AI engineers who need spoken-word text to index alongside the metadata.
What YouTube video data is publicly available to scrape?
A public YouTube watch page exposes, to any signed-out visitor, the video's title, full description, publish date, duration, view count, creator-set tags, category, language, thumbnail set, live status, and the uploading channel's name, UC… ID, handle, avatar and verified badge. Caption tracks are public whenever the creator or YouTube's automatic captioning produced one.
| Data Category | Publicly visible signed out | Gated behind a Google sign-in, or not collected here |
|---|---|---|
| Title, full description, publish date, duration | ✅ Public | — |
| View count | ✅ Public | — |
| Like count | ✅ Public when YouTube exposes it | Returned as null when it is hidden for that video |
| Tags, category, language, live status | ✅ Public | — |
| Thumbnail images and channel avatar | ✅ Public | — |
| Caption / subtitle tracks | ✅ Public when a track exists | transcript is null when the video has none |
Channel UC… ID, name, handle, subscriber count, verified badge | ✅ Public | Subscriber count is an empty string when the channel hides it |
| Dislike count | ❌ | Removed from public display by YouTube in 2021 |
| Comment bodies and replies | ❌ | Public on the page, but deliberately not collected — only the total comment_count |
| Chapter markers and related-video lists | ❌ | Not collected |
| Age-restricted videos | ❌ | Google sign-in — and there is no cookie field in this Actor |
| Private, deleted and members-only videos | ❌ | Login or channel membership |
YouTube Video Details Scraper only returns publicly visible data — what any signed-out visitor sees. Nothing behind a login wall.
What data can I extract with YouTube Video Details Scraper?
Each row carries the video's descriptive fields, its numeric performance metrics, a nested channel object, a thumbnail map and the transcript cue list. Twenty-four keys on a success row and twenty-five distinct top-level keys across both row types, plus seven nested keys on channel, up to five on thumbnails, and three on every transcript cue.
| Field Name | Description |
|---|---|
type | Constant video. Present on every row |
video_id | The 11-character YouTube video ID |
title | Video title, or null if YouTube reported none |
description | The complete description text, untruncated. An empty string when the video has no description |
channel_id | The real UC… channel ID, not the mutable @handle |
channel_name | Channel display name |
published_date | Publish date normalized to YYYY-MM-DD. null when YouTube reported no upload date |
duration_seconds | Runtime in seconds, as an integer |
views | View count as an exact integer, not an abbreviated display string |
likes | Like count as an integer, or null when YouTube does not expose one for that video |
comment_count | Total comments YouTube reports. Comment bodies are not collected |
tags | Array of the creator's keyword tags. Empty array when the video has none |
thumbnails | Object mapping size names to image URLs. Shape documented below |
channel | Nested channel object — seven keys, documented below |
transcript | Array of timed caption cues, or null when no usable track was found. Shape documented below |
category | The first YouTube category on the video, e.g. Music. null when absent |
language | Video language code as YouTube reports it, e.g. en. null when absent |
live_status | YouTube's own live status string, e.g. not_live, was_live, is_live, is_upcoming, post_live. null when absent |
engagement_rate | (likes + comments) / views, rounded to four decimal places. null when the view count is unknown or zero |
hashtags | Hashtags parsed out of the description, without the leading #. Empty array when there are none |
upload_type | short, live or normal |
resolution | True maximum resolution as WIDTHxHEIGHT, e.g. 3840x2160. null when no format declared a height |
success | Boolean. true only on rows that carry real extracted data. Present on every row |
inputUrl | The URL string you supplied, verbatim — not the normalized watch URL |
error | Failure reason. Written on failed and rejected rows only — the key is absent from every success row |
Descriptive and identity fields
description is returned in full. There is no character cap, no first-paragraph cut and no ellipsis — whatever the creator wrote is what lands in the field, newlines included. hashtags is derived from that same text, so a video whose tags live only in its description still yields a usable tag list; the leading # is stripped and only hashtags starting with a word character are kept.
upload_type is derived from two real signals rather than guessed. A /shorts/ path in the URL you supplied gives short; a live or formerly-live live_status gives live; everything else is normal. A duration threshold is deliberately not used, so a genuine Short submitted as a watch?v= URL is reported as normal rather than mislabelled — if Shorts classification matters to your pipeline, submit Shorts as /shorts/ links.
channel carries id (the UC… ID), name, handle, url, subscriberCount, logo and badges. Two details to code around. subscriberCount is a string in the form 4520000 subscribers, not an integer, and an empty string when YouTube exposes no count — parse it before doing arithmetic. And handle is inconsistent by source: when it is derived from an /@name channel URL it has no leading @, and when it falls back to YouTube's uploader ID it does. Strip a leading @ before comparing handles. logo is the channel avatar URL, fetched once per channel per run from that channel's About page and cached, and it is an empty string if that fetch fails. badges is ["Verified"] or [].
Metric, media and transcript fields
views, likes, comment_count and duration_seconds come back as integers. likes is the one to guard: YouTube hides the like count on some videos, and when it does the field is null rather than a fabricated 0. That has a knock-on effect worth knowing — engagement_rate treats a missing like count as zero when it computes (likes + comments) / views, so an engagement rate on a video with hidden likes understates the true figure. If likes is null, recompute or discard the rate.
thumbnails is an object keyed by size — default, medium, high, standard, maxres — holding only the sizes YouTube actually publishes for that video. Older uploads commonly lack standard and maxres, and those keys are simply not present rather than set to null. resolution is computed from the complete format list, adaptive formats included, so a 4K video reports 4K.
transcript is an array of cues, one per caption event, each with three keys:
| Cue key | Description |
|---|---|
start | Cue start time in seconds, as a string formatted to three decimals, e.g. 18.800 |
dur | Cue duration in seconds, same string format, e.g. 3.000 |
text | The cue's text, whitespace-collapsed |
start and dur are strings, not numbers — cast them before arithmetic. Cues are sorted by start time and clamped so that an overlapping auto-generated cue never runs past the next cue's start. Human-uploaded subtitles are preferred over automatic captions, in the video's own language first, then English, then whatever track exists. When no track exists, or the caption endpoint refuses, transcript is null — never an empty list and never fabricated cues.
🤖 Add-on: Need additional YouTube data?
Companion Scraper-Engine Actors cover the surfaces this one deliberately leaves out. YouTube Search Scraper and YouTube Playlist Scraper find the video URLs to feed in here. YouTube Channel Finder resolves channels from names and handles when you need channel-level context rather than per-video detail, and YouTube Community Posts Scraper covers the community tab.
How does YouTube Video Details Scraper differ from the official YouTube Data API?
Honestly: the YouTube Data API v3 is public, documented and covers video metadata well, and for a lot of jobs it is the better choice. The differences that matter are setup, governance and caption access rather than raw metadata coverage. Every constraint below should be verified against Google's current published YouTube Data API documentation before you commit to either route — the terms change and no figures from them are reproduced here.
| Feature | YouTube Data API v3 | YouTube Video Details Scraper |
|---|---|---|
| Access setup | Google Cloud project and API key; OAuth for owner-scoped operations | ✅ Apify account and token only |
| Usage governance | Daily quota units consumed per call — verify current costs against Google's published documentation | ✅ Apify platform usage, plus one video_result event per successful video |
| Caption text for videos you do not own | ❌ The caption download endpoint is documented as requiring the video owner's authorization — verify against Google's current published documentation | ✅ Public caption track returned as timed cues on transcript |
| Response shape | Separate resources for video, channel and caption data | ✅ One row joining video metadata, channel object and transcript |
| Terms alignment | ✅ Google's own sanctioned interface, governed by the YouTube API Services Terms of Service | You own the terms-of-service assessment for your use case |
| Field stability | ✅ Versioned and documented by Google | Reflects what the public page exposes; a missing value returns null |
Use the official API when you are shipping a product that needs contractual certainty, when you need authenticated operations on your own channel, or when you want a versioned schema Google commits to. Use YouTube Video Details Scraper when you need transcript text for videos you do not own, when a Google Cloud project is more setup than the job warrants, or when you want the video, its channel and its captions joined into a single row instead of stitched together from separate calls.
How to use YouTube Video Details Scraper
YouTube Video Details Scraper runs on Apify. Start it from the Apify Console, or call it through the Apify API.
- Open YouTube Video Details Scraper on Apify and click Try for free
- Paste your video links into YouTube video URLs (
startUrls), one per line — this is the only required input - Leave Proxy configuration (
proxyConfiguration) on its default of Apify Proxy with theRESIDENTIALgroup, unless you have a reason to change it - Click Start. URLs are processed in order and each row appears in the dataset as that video finishes
- Download the dataset as JSON, CSV, Excel, XML or HTML, or read it through the Apify API
Playlist and channel URLs are not accepted. They are rejected with an explicit reason instead of producing a malformed row, and those rows are not charged.
How to scale to bulk video extraction
startUrls is a list with no length cap in the schema and none in the Actor, so a single run can cover as many videos as you want to paste. Videos are processed strictly one at a time, with a one-second pause between them, so runtime scales roughly linearly with list length.
Two behaviours to plan around. There is no de-duplication — the same video listed twice is fetched twice and produces two charged rows, so de-duplicate your list before the run, remembering that https://youtu.be/ID and https://www.youtube.com/watch?v=ID are the same video. And the run is not transactional: rows are pushed live as each URL finishes, so a run you abort early keeps everything already written.
What can you do with YouTube video data?
- 🔍 An SEO analyst reverse-engineering what ranks pulls
tags,title,descriptionandhashtagsacross the top results for a keyword, then joins onviewsandpublished_dateto see which tag patterns correlate with traction. - 📈 A content strategist benchmarking competitors tracks
views,likes,comment_countandengagement_ratepervideo_idacross scheduled runs, usingduration_secondsandupload_typeto separate Shorts performance from long-form. - 🎙️ A media researcher studying what was actually said indexes
transcriptcues with theirstarttimes, so a quote can be cited back to its exact second in the source video. - 🤝 A partnerships manager vetting creators reads
channel.subscriberCount,channel.badgesand per-videoengagement_ratefrom one row, instead of cross-referencing a channel page against each video. - 🤖 An AI engineer building a video RAG pipeline chunks
transcripttext into a vector store keyed onvideo_id, withtitle,descriptionandpublished_dateas metadata filters andinputUrlas the citation anchor — spoken content becomes searchable without a separate transcription step.
Every one of these is callable from an agent framework over the Apify API, since the Actor is a standard HTTP-triggered run.
How does YouTube Video Details Scraper handle rate limits and blocking?
No CAPTCHA is solved and no browser is launched. What the Actor handles is IP-level refusal, which on YouTube usually surfaces as a "Sign in to confirm you're not a bot" interstitial, an HTTP 429 or an HTTP 403.
Each video gets up to three extraction attempts with a 30-second socket timeout per request and an exponential back-off between them — 2 seconds, then 4, then 8. Between attempts the Actor reacts to the error it actually got: if the message matches a known bot-wall signature it escalates the proxy route one rung, and otherwise it rotates to a fresh exit session on the same rung. The ladder is direct → datacenter → residential; once it reaches residential, further failures rotate the session rather than escalate. Transcript fetching has its own smaller loop of three attempts with 1.5-second and 3-second waits, retried only on HTTP 429, 403 and 503 and abandoned immediately on any other status.
If all three attempts fail, the video is written as a row with success: false and a cleaned error message on error, the run continues with your remaining URLs, and you are not charged for it. Residential is the default proxy group because YouTube bot-walls datacenter ranges intermittently.
⬇️ Input
Two parameters, one of them required. There is nothing else to configure — no cookies, no API key, no result cap, no concurrency setting.
| Parameter | Required | Type | Description | Example Value |
|---|---|---|---|---|
startUrls | Yes | array | YouTube video URLs, one per line. Accepts https://www.youtube.com/watch?v=ID, https://youtu.be/ID, /shorts/ID, /live/ID, /embed/ID, and bare 11-character video IDs. Playlist and channel URLs are rejected with a reason instead of producing a malformed row. Editor is a string list; no minimum, maximum or item-count limit is set. Prefilled with one watch URL. | ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"] |
proxyConfiguration | No | object | Apify Proxy settings. Defaults and prefills to {"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]}. | {"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]} |
On startUrls: this is the required parameter, and a run that supplies an empty list does not fail — it logs No URLs provided in startUrls -- nothing to do. and exits immediately with zero rows and zero charges.
Every entry is normalized before extraction. A bare 11-character ID becomes a watch URL; youtu.be, /shorts/, /live/ and /embed/ links have the ID pulled out and rebuilt as https://www.youtube.com/watch?v=ID; a string with no scheme has https:// prepended. A watch URL that also carries a list= parameter is fine — the playlist part is dropped and only that video is scraped. Three shapes are rejected outright, each producing an uncharged row whose error names the reason: an empty string (empty_input), a playlist URL (playlist_url_not_supported), and a channel URL in /@name, /channel/, /c/ or /user/ form (channel_url_not_supported). One edge to know: because the playlist check runs first, a youtu.be/ID?list=… link is rejected as a playlist even though it names a specific video — strip the list= parameter, or use the watch?v= form.
There is one input shape the schema does not advertise: as well as plain strings, startUrls accepts { "url": "https://www.youtube.com/watch?v=ID" } objects, so output from another tool that emits request-list-style records can usually be fed in unchanged.
On proxyConfiguration: your configuration sets the starting rung, not a ceiling. Your object is passed through as given for the first request, so custom proxyUrls and non-default Apify groups work for that initial route. But when the Actor rotates or escalates after a failure it switches to its own groups — Apify datacenter, then RESIDENTIAL — rather than re-using a custom group or a supplied proxy URL. The same applies in reverse: setting useApifyProxy: false starts the run on the container's direct IP, and the first bot-wall escalates it onto Apify Proxy anyway. If proxy setup fails at any point — for example on a plan without residential access — a warning is logged and the run continues on the direct connection rather than aborting.
Example input
{"startUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ","https://youtu.be/jNQXAC9IVRw","https://www.youtube.com/shorts/1P0xLRIqSFo","aqz-KE-bpKQ"],"proxyConfiguration": {"useApifyProxy": true,"apifyProxyGroups": ["RESIDENTIAL"]}}
⬆️ Output
One dataset row per input URL, pushed live as soon as that video finishes, in the order you supplied them. Typed JSON with stable key names across runs — no HTML, no selectors. Export as JSON, CSV, Excel, XML or HTML, or read the dataset through the Apify API.
Rows stay rectangular, which matters for CSV exports. A failed or rejected row carries the same key set as a success row, with null in the scalar fields and [] or {} in the collection fields — no fabricated zeros. The single exception is error, which is written on failed and rejected rows only and is absent from success rows, so read it with .get().
Each successful video is billed as one video_result event. Failed and rejected rows are pushed deliberately uncharged — a URL that produced no data must not bill. The marker is the boolean success field:
videos = [row for row in items if row["success"]]
That single filter covers every uncharged case: extraction failures, playlist URLs, channel URLs and empty entries alike.
Example output
A success row for a video that has a caption track. transcript is trimmed to three cues here; a real row carries every caption event in the track.
{"type": "video","video_id": "dQw4w9WgXcQ","title": "Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)","description": "The official video for “Never Gonna Give You Up” by Rick Astley.\n\nNever: The Autobiography 📚 OUT NOW!\n\n#RickAstley #NeverGonnaGiveYouUp #WhenevrYouNeedSomebody","channel_id": "UCuAXFkgsw1L7xaCfnd5JJOw","channel_name": "Rick Astley","published_date": "2009-10-25","duration_seconds": 213,"views": 1794607166,"likes": 18565061,"comment_count": 2413902,"tags": ["rick astley", "Never Gonna Give You Up", "nggyu", "80s music"],"thumbnails": {"default": "https://i.ytimg.com/vi/dQw4w9WgXcQ/default.jpg","medium": "https://i.ytimg.com/vi/dQw4w9WgXcQ/mqdefault.jpg","high": "https://i.ytimg.com/vi/dQw4w9WgXcQ/hqdefault.jpg","standard": "https://i.ytimg.com/vi/dQw4w9WgXcQ/sddefault.jpg","maxres": "https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg"},"channel": {"id": "UCuAXFkgsw1L7xaCfnd5JJOw","name": "Rick Astley","handle": "RickAstleyYT","url": "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw","subscriberCount": "4520000 subscribers","logo": "https://yt3.googleusercontent.com/ytc/AIdro_kX9zYtQpVmH2sJcRfLbN7wTgEo4KqZ1vBxUiMa=s900-c-k-c0x00ffffff-no-rj","badges": ["Verified"]},"transcript": [{ "start": "0.320", "dur": "14.260", "text": "[Music]" },{ "start": "18.800", "dur": "3.000", "text": "We're no strangers to love" },{ "start": "21.800", "dur": "4.320", "text": "You know the rules and so do I" }],"category": "Music","language": "en","live_status": "not_live","engagement_rate": 0.0117,"hashtags": ["RickAstley", "NeverGonnaGiveYouUp", "WhenevrYouNeedSomebody"],"upload_type": "normal","resolution": "3840x2160","success": true,"inputUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"}
An uncharged row, produced here by a playlist URL that was rejected before any request was made:
{"type": "video","video_id": null,"title": null,"description": null,"channel_id": null,"channel_name": null,"published_date": null,"duration_seconds": null,"views": null,"likes": null,"comment_count": null,"tags": [],"thumbnails": {},"channel": {},"transcript": null,"category": null,"language": null,"live_status": null,"engagement_rate": null,"hashtags": [],"upload_type": null,"resolution": null,"success": false,"inputUrl": "https://www.youtube.com/playlist?list=PLObrtcm1Kw6Odq5ks2R3bbJUGVVwQF-vw","error": "playlist_url_not_supported"}
How does it work?
YouTube Video Details Scraper normalizes each URL you supply into a canonical watch link, then asks YouTube for that video's public data through the yt-dlp extractor with downloading switched off — no media bytes are ever transferred, and the format list is read only to compute the true maximum resolution. Requests go out through your proxy configuration, with up to three attempts per video and an automatic route change between them when YouTube answers with a bot check.
Captions are a second, separate step. The Actor picks the best available track — human subtitles before automatic captions, the video's own language before English — fetches it in YouTube's timed JSON format during the run, and rebuilds it into one cue per caption event with real start times and durations. The channel avatar comes from a single cached fetch of that channel's About page, so a run covering fifty videos from one channel fetches it once.
Only publicly visible data is collected, with no account, cookie or token at any point. Because the row shape is defined by this Actor rather than by YouTube's markup, a front-end redesign does not change your field names — a moved value nulls one field instead of breaking the row.
Integrations
YouTube Video Details Scraper is an Apify Actor, so it works with anything that can call the Apify API or consume a dataset — schedules, webhooks, no-code platforms and agent frameworks included.
Calling YouTube Video Details Scraper from Python
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("<YOUR_USERNAME>/youtube-video-details-scraper").call(run_input={"startUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ","https://youtu.be/jNQXAC9IVRw",],"proxyConfiguration": {"useApifyProxy": True, "apifyProxyGroups": ["RESIDENTIAL"]},})for row in client.dataset(run["defaultDatasetId"]).iterate_items():if not row["success"]:print("skipped", row["inputUrl"], row.get("error"))continuecues = row["transcript"] or []print(row["video_id"], row["views"], row["likes"], f"{len(cues)} cues")
Works in Go, Ruby, Node.js, cURL — any language that can make an HTTP request. Branch on success and you are left with charged results only.
No-code tools (n8n, Make, Zapier)
In n8n, use the Apify node — or an HTTP Request node pointed at the Apify run endpoint with your token — and pass the same JSON input shown above; a Filter node on success drops the uncharged rows before anything downstream sees them. In Make, the Apify module supports run-and-wait, so a batch of video links can feed a Google Sheets or Airtable step directly. Apify's own schedules and webhooks cover the recurring case with no external tool at all: schedule a weekly sweep of a URL list and have a webhook push each finished dataset into your storage.
Is it legal to scrape YouTube video details?
Video titles, descriptions, view counts, durations, tags and captions are content metadata published for public discovery, and YouTube Video Details Scraper collects only what a signed-out visitor sees — no account, no login, no API key.
Because the output is content metadata rather than personal data, the regimes that govern a profile scraper do not attach here in the same way. No viewer identity, comment author, watch history or contact detail is collected; GDPR and CCPA obligations that would apply to a dataset of individual people's profiles do not follow from a dataset of video statistics. The one nuance worth naming: a channel is not always an organisation — an individual creator's channel identifies a person, so if your dataset is built around individual creators rather than videos, treat those channel fields with the care personal data warrants.
The obligations that do apply are contractual and copyright-related. YouTube's terms of service govern your access independently, and description, title and especially transcript are the creator's expressive content — republishing them wholesale is a copyright question, not a data-protection one. Consult legal counsel before redistributing collected descriptions or transcripts at scale.
❓ Frequently asked questions
What YouTube video fields does YouTube Video Details Scraper return?
The five most used are title, views, transcript, tags and description. A success row carries 24 keys, with 25 distinct top-level keys across both row types, plus a nested channel object, a thumbnails map and per-cue transcript keys — see the data fields table above for all of them.
Does YouTube Video Details Scraper return transcripts or captions?
Yes — that is the field this Actor is built around. transcript is an array of timed cues, one per caption event, each with start, dur and text. Human-uploaded subtitles are preferred over automatic captions, in the video's own language first and English second. When a video has no usable caption track the field is null rather than an empty list, so you can tell "no captions" apart from "captions with no text". Note that the cue start and dur values are strings formatted to three decimals, not numbers.
Does it return a direct video download or stream URL?
No. The Actor runs with downloading disabled and emits no playable media link of any kind — no progressive MP4, no DASH or HLS manifest, no audio stream and no formats array. The format list is read only to compute resolution. The only URLs in the output are the thumbnail images on thumbnails, the channel avatar on channel.logo, and inputUrl — the link you supplied.
Is the description truncated?
No. description carries the complete description text as the creator wrote it, newlines and all, with no character cap and no ellipsis. hashtags is parsed from that same full text.
Why is likes sometimes null, and are dislikes available?
likes is null when YouTube does not expose a like count for that video — the field is never filled with a fabricated 0. Watch the knock-on effect: engagement_rate counts a missing like total as zero when it computes (likes + comments) / views, so on a video with hidden likes the rate understates reality. Dislikes are not available from any source: YouTube removed the public dislike count in 2021.
Does YouTube Video Details Scraper require a YouTube account, login or API key?
No. The Actor runs signed out end to end. There is no cookie, token, OAuth or API-key field in the input schema and none is used at runtime, and no Google Cloud project is involved. The only credential you need is your Apify token. The trade-off is that age-restricted videos, which require a Google sign-in, cannot be extracted.
What happens if a video is private, deleted, age-restricted or region-blocked?
You get one row with success: false and YouTube's own reason on error, and you are not charged. All four cases share the same path: yt-dlp reports the video as unavailable, the Actor retries up to three times with a proxy rotation between attempts — so expect roughly fourteen seconds of back-off before a genuinely dead video is written off — and then writes the failure row with every data field nulled rather than guessed. The run continues with your remaining URLs. Playlist and channel URLs are different: they are rejected before any request is made, so they cost no time at all, with error set to playlist_url_not_supported or channel_url_not_supported.
How many videos can I extract in one run, and what am I charged for?
There is no cap in the schema and none in the Actor — paste as many video URLs as you like into startUrls. Processing is strictly sequential with a one-second pause between videos, so runtime scales roughly linearly with list length; each video also allows up to three attempts with 2, 4 and 8-second back-offs and a 30-second socket timeout per request. Charging is per outcome: each successful video bills one video_result event, while failed and rejected rows are pushed uncharged. There is no de-duplication, so the same video listed twice is fetched twice and charged twice.
Does YouTube Video Details Scraper work with Claude, ChatGPT and other AI agent tools?
Yes. It is callable as a standard HTTP endpoint through the Apify API, so LangChain, CrewAI, n8n or a hand-written tool definition can invoke it and receive typed JSON with no parsing step. Give the agent a list of video URLs and have it branch on success.
How does YouTube Video Details Scraper compare to other YouTube video detail scrapers?
Checked on the Apify Store on 25 July 2026. beyondops/youtube-metadata-scraper-pro-v2 documents an eleven-column output — channel, channel_url, upload_date, url, title, duration, views, likes, comment_count, description and status — and states in its own column dictionary that description is the "First 200 characters of the video description"; it offers a Netscape cookies input for age-restricted content, which this Actor does not, and its listing does not document a transcript, tags, category, language, resolution, hashtag or engagement-rate field. logiover/youtube-video-details-scraper documents fourteen fields including the full description, a keywords tag array, category and a single max-resolution thumbnail, plus includeLikes and maxResults inputs this Actor does not have; its support section invites users to request "engagement rate, comment counts, or chapter/timestamp extraction", and its listing does not document a transcript field. scrapepilotapi/youtube-video-details-scraper could not be retrieved when checked on that date, so nothing about it is documented here. What this Actor documents that those listings do not is timed transcript cues, a full thumbnail size map, the real UC… channel ID alongside the handle, true maximum resolution from the complete format list, and uncharged failure rows. Silence on a listing is not the same as a missing feature.
Does YouTube Video Details Scraper return data in a format LLMs can use directly?
Yes. Rows are typed, normalized JSON with the same key names on every run — no HTML parsing, no selectors. Rows stay rectangular across success and failure, so a CSV export has stable columns; the only key that varies is error, which is absent on success rows, so read it with .get().
What happens when YouTube changes its layout or anti-bot system?
The scraper is maintained, and because it reads YouTube's own structured video data rather than rendered markup, a visual redesign generally does not affect it. When an upstream key does move, the affected field returns null rather than a stale or fabricated value and the row still arrives with your field names intact. Bot-wall detection is keyed on the error text YouTube returns rather than on a status code alone, which is the check most likely to survive an upstream change.
Can I use YouTube Video Details Scraper without managing proxies or browser infrastructure?
Yes. There is no browser to run and no proxy account to create — tick Apify Proxy and the route is handled for you, defaulting to the residential group. Be clear about what it does not do: it does not solve CAPTCHAs, and it cannot sign in, so an age-restricted video stays out of reach. Your proxy choice sets the starting rung only; after a bot-wall the Actor escalates through datacenter to residential using its own groups.
Which YouTube video fields work best for AI training data and RAG indexing?
For RAG indexing: transcript is by far the highest-information text field and chunks cleanly by cue, with description as the second body of free text, title as a short label and inputUrl plus a cue start as a citation anchor down to the second. For training data: duration_seconds, views, published_date, resolution, upload_type and live_status are the most structurally consistent fields across records, and video_id and channel_id are stable partition keys. All values return as typed primitives, arrays or plain nested objects — just remember that start and dur inside transcript cues are strings.
🔗 Related scrapers
| Scraper Name | What it extracts |
|---|---|
| YouTube Search Scraper | Videos matching a keyword, when you need to find URLs before hydrating them here |
| YouTube Playlist Scraper | Every video in a playlist, with channel and playlist context on each row |
| YouTube Channel Finder | Channels resolved from names and handles |
| YouTube Community Posts Scraper | Posts from a channel's community tab |
| YouTube Shorts Scraper Creator Lead Enrichment | Short-form video metadata with creator contact enrichment |
| TikTok Video Scraper Creator Profile Contact | The same per-video detail job on TikTok, with creator profile data |
A common pairing: collect video URLs with YouTube Search Scraper or YouTube Playlist Scraper, then feed those URLs into this Actor to hydrate each one into a full record with its transcript.
💬 Your feedback
Found a bug, or missing a field YouTube exposes that is not in the output? Open an issue on the Actor's Issues tab. Reports that include the exact video URL and the input JSON you ran are the fastest to reproduce and fix.