Youtube Video Details Scraper
Pricing
from $5.99 / 1,000 results
Youtube Video Details Scraper
YouTube Video Details Scraper extracts video titles, descriptions, tags, view counts, likes, comments, upload dates, channel information, and more from YouTube videos. Ideal for SEO analysis, competitor research, content tracking, market research, and data-driven decision-making.
Pricing
from $5.99 / 1,000 results
Rating
0.0
(0)
Developer
ScrapeVanta
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
7 days ago
Last modified
Categories
Share
YouTube Video Details Scraper — Metadata, Engagement Metrics and Searchable Transcripts
Pull full details for any YouTube video, or point it at a channel or playlist and let it expand that into videos for you. Every record carries the real numbers, derived engagement metrics, creator chapters, and a transcript you can actually search — with timestamps and links that jump straight to the moment.
No API key. No quota.
What it does
1. Give it whatever link you have
Videos, channels and playlists all work, in every URL form people actually paste:
| You paste | It understands |
|---|---|
youtube.com/watch?v=…, youtu.be/…, /shorts/…, /live/…, /embed/… | A single video |
| A bare 11-character ID | A single video |
youtube.com/@handle, or just @handle | The channel's recent uploads |
youtube.com/channel/UC…, or a bare UC… ID | The channel's recent uploads |
youtube.com/playlist?list=PL…, or a bare playlist ID | The playlist's videos |
Channels and playlists are expanded through YouTube's own public feed — a documented endpoint that needs no key and no quota. Handles are resolved to a channel ID automatically.
Anything unrecognised is reported back to you by name rather than silently dropped, so a run never quietly comes up short.
2. Search inside the transcript
Give it search terms and every match comes back with a timestamp, the surrounding sentence, and a link that opens the video at that second.
The important detail: phrases are matched across caption boundaries. Captions break wherever the line ran out, so "machine learning" is routinely split into …about machine / learning and…. Matching fragment by fragment misses those. The transcript is joined first and matches are traced back to the fragment that contains them, which is how each hit still gets an accurate timestamp.
Alongside search you get the transcript as readable plain text (caption artefacts like [Music] and >> SPEAKER: removed), a word count, the speaking rate in words per minute, transcript coverage, and the most frequent meaningful words with their share of the transcript.
3. Engagement metrics, honestly derived
| Field | What it is |
|---|---|
engagementRatePercent | (likes + comments) ÷ views, as a percentage |
likeRatePercent | likes ÷ views |
commentRatePercent | comments ÷ views |
viewsPerDay | views ÷ days since publication |
videoAgeDays | days since publication |
Sort by any of them, or filter on views, duration, publish date, keyword, or "must have a transcript".
Where the numbers come from, since it matters: the view count and like count are exact figures read from the page. The comment count is only ever published rounded ("2.4M") on videos of any size, so it is named commentCountApprox and the original label is kept in commentCountText — a rounded number is not presented as a precise one. Engagement rate is a conventional proxy computed from public counts; views are not unique viewers.
4. Chapters, tags and format
Creator chapter markers are read out of the description and returned with start time, end time, duration and a deep link. Timestamps that aren't chapters — links to other videos, track listings — are rejected by requiring them to ascend and to fall inside the runtime.
isShortFormat comes from the canonical URL, which is the only reliable signal. (Requesting /shorts/<id> directly proves nothing: it redirects for every video, Short or not.)
maxResolution and maxFps are read from the actual stream list, so a 4K video reports 4K.
Input
| Field | Type | Default | Description |
|---|---|---|---|
videoUrls | array | — | Videos, in any URL form or as bare IDs |
channelUrls | array | — | Channel links, @handles or UC… IDs |
playlistUrls | array | — | Playlist links or IDs |
maxVideosPerSource | integer | 10 | Videos to take from each channel/playlist |
includeTranscript | boolean | true | Fetch and analyse captions |
transcriptLanguages | array | ["en"] | Preferred languages, in order |
transcriptSearchTerms | array | — | Terms to locate, with timestamps |
includeTranscriptSnippets | boolean | false | Include every timed caption segment |
keywordCount | integer | 15 | Keywords to report per video |
includeChapters | boolean | true | Extract chapter markers |
includeDescription | boolean | true | Keep the full description |
minViewCount | integer | — | Drop videos below this |
minDurationSeconds | integer | — | Drop shorter videos (61 excludes Shorts) |
maxDurationSeconds | integer | — | Drop longer videos |
publishedAfter | string | — | YYYY-MM-DD or ISO timestamp |
filterKeywords | array | — | Title/description must contain one |
requireTranscript | boolean | false | Only keep videos with captions |
sortBy | string | discovery order | Views, likes, date, engagement, … |
sortDescending | boolean | true | Highest first |
concurrentRequests | integer | 5 | Videos fetched at once |
emitRunSummary | boolean | true | Append the aggregate record |
proxyConfig | object | Apify Proxy on | Proxy settings; effectively required on the platform |
At least one of videoUrls, channelUrls or playlistUrls is required.
Example input
{"channelUrls": ["@RickAstleyYT"],"maxVideosPerSource": 10,"includeTranscript": true,"transcriptSearchTerms": ["never gonna give you up"],"minViewCount": 10000,"sortBy": "engagementRatePercent","sortDescending": true}
Output
One video record per video, then an optional summary.
Video record fields
Identity
| Field | Description |
|---|---|
videoId, videoUrl, canonicalUrl | The video's ID, a watch link, and YouTube's own canonical link |
videoTitle, description | Title and full description (description omitted if you turn it off) |
channelName, channelId, channelHandle, channelUrl | Who published it |
subscriberCountText, subscriberCountApprox | Channel size as shown, and parsed to a number |
discoveredVia | Whether this video came from a direct link, a channel feed or a playlist feed |
scrapedAt | When this row was taken |
Timing and format
| Field | Description |
|---|---|
publishedAt, uploadedAt | Publish and upload timestamps (they differ for scheduled videos) |
durationSeconds, durationText | Runtime in seconds and as M:SS / H:MM:SS |
isShortFormat | Whether it's a Short, from the canonical URL |
isLiveContent, isPrivate, isUnlisted, isFamilySafe, allowRatings | Status flags as YouTube reports them |
category, audioLanguage | Category, and the declared audio language when the video sets one |
maxResolution, maxWidth, maxHeight, maxQualityLabel, maxFps | Highest quality actually offered |
thumbnailUrl | Largest available thumbnail |
Counts and engagement
| Field | Description |
|---|---|
viewCount, likeCount | Exact figures |
commentCountApprox, commentCountText | Rounded comment count, and YouTube's original label |
ratingAverage, ratingCount | Star rating, when the video arrived via a feed that carried it |
engagementRatePercent, likeRatePercent, commentRatePercent | Ratios against views |
viewsPerDay, videoAgeDays | Reach per day, and age |
Content
| Field | Description |
|---|---|
tags, hashtags | Creator tags, and hashtags found in the title and description |
chapters, chapterCount | Chapter markers with start, end, duration and title |
hasCaptions, captionLanguages | Whether captions exist, and in which languages |
Transcript (when includeTranscript is on)
| Field | Description |
|---|---|
transcriptAvailable, transcriptError, transcriptLanguage | Whether a transcript was retrieved, and why not if it wasn't |
transcriptText | Cleaned, readable plain text |
transcriptWordCount, transcriptCharacterCount | Length |
speakingRateWpm, readingTimeMinutes, transcriptCoveragePercent | Pace, reading time, and how much of the runtime the captions span |
topKeywords | Most frequent meaningful words with counts and shares |
searchHits, searchHitTotal | Matches for your search terms, with timestamps and deep links |
transcriptSnippets | Every timed caption segment (only when you ask for it) |
Failure
| Field | Description |
|---|---|
fetchFailed, fetchError | Whether the video could be read, and the reason |
Example video record
{"recordType": "video","videoId": "dQw4w9WgXcQ","videoUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ","videoTitle": "Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)","channelName": "Rick Astley","channelId": "UCuAXFkgsw1L7xaCfnd5JJOw","channelHandle": "@RickAstleyYT","subscriberCountText": "4.53M subscribers","subscriberCountApprox": 4530000,"publishedAt": "2009-10-24T23:57:33-07:00","durationSeconds": 213,"durationText": "3:33","viewCount": 1803235213,"likeCount": 19332287,"commentCountApprox": 2400000,"commentCountText": "2.4M","engagementRatePercent": 1.2052,"likeRatePercent": 1.0721,"viewsPerDay": 293512,"videoAgeDays": 6136.0,"category": "Music","isShortFormat": false,"isLiveContent": false,"isFamilySafe": true,"maxResolution": "3840x2160","maxFps": 25,"tags": ["rick astley", "Never Gonna Give You Up", "nggyu"],"hashtags": [],"hasCaptions": true,"captionLanguages": ["en", "de-DE", "ja"],"transcriptLanguage": "en","transcriptWordCount": 366,"speakingRateWpm": 103.1,"transcriptCoveragePercent": 99.2,"topKeywords": [{ "keyword": "gonna", "occurrences": 24, "sharePercent": 14.55 }],"searchHits": [{"term": "never gonna give you up","matchCount": 6,"occurrences": [{"startSeconds": 43.0,"startTime": "0:43","context": "…we're no strangers to love never gonna give you up never gonna let you down…","linkUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=43s"}]}],"chapters": [],"chapterCount": 0,"discoveredVia": "direct link","fetchFailed": false,"scrapedAt": "2026-08-12T09:00:00+00:00"}
A video that cannot be read still produces a row with fetchFailed: true and the reason in fetchError. Where possible the title and channel are filled in from YouTube's public oEmbed endpoint, so a blocked page still tells you which video failed.
Summary record
{"recordType": "summary","videosAttempted": 10,"videosSucceeded": 10,"videosFailed": 0,"failedVideoIds": [],"sourcesRequested": ["@RickAstleyYT"],"inputsRejected": [],"totalLikes": 21400418,"transcriptsRetrieved": 8,"shortsCount": 3,"totalViews": 2104882133,"averageViews": 210488213,"medianViews": 270575.0,"averageEngagementRatePercent": 2.41,"averageDurationSeconds": 128.4,"totalTranscriptWords": 4820,"channelBreakdown": { "Rick Astley": 10 },"categoryBreakdown": { "Music": 8, "Entertainment": 2 },"topTags": [{ "tag": "rick astley", "videoCount": 6 }],"mostViewedVideoId": "dQw4w9WgXcQ","mostViewedVideoTitle": "Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)","mostEngagingVideoId": "JjI4o2w6D5A","finishedAt": "2026-08-12T09:00:22+00:00"}
Common use cases
- Content research — pull a competitor's recent uploads and sort by engagement rate to see what actually lands, not just what got views.
- Finding the moment — search a long interview or conference talk for a topic and get links straight to every mention.
- Repurposing — the cleaned transcript, chapters and keyword profile are the raw material for blog posts, show notes and clips.
- SEO and tag research —
topTagsacross a channel's catalogue shows what they consistently tag for. - Monitoring — run on a schedule against a channel and track
viewsPerDayas videos age. - Dataset building — transcripts plus metadata for a set of videos, in one pass.
Notes and limits
- The public feed is short. Channel and playlist expansion returns roughly the 15 most recent items and offers no paging, so
maxVideosPerSourcecannot exceed what the feed holds. To go deeper, supply video URLs directly. The run log says when the feed was the limiting factor. - Comment counts are rounded by YouTube, not by this Actor. Large videos publish "2.4M" and nothing more precise.
commentCountApproxcarries the parsed number,commentCountTextthe original label. - Transcripts depend on the video having captions. Many do not, and some creators disable them.
transcriptAvailableandtranscriptErrorsay which case you hit, per video, instead of returning an empty string that looks like a silent video. - Run this with a proxy. Apify's shared outbound addresses are heavily used against YouTube, and a run without
proxyConfigis answered with "Sign in to confirm you're not a bot" for most videos. Measured on the platform: with no proxy, 1 of 4 videos returned data; with Apify Proxy enabled, 5 of 5 returned data and transcripts. Either the default datacenter group or a residential group works; residential holds up better across long runs. - Videos that fail this way still produce a row. Titles, view counts, publish dates and the Shorts flag come from the public feed when a channel or playlist supplied them, so a challenged run degrades to less data rather than to none.
- Auto-generated captions contain errors. Speaking rate, word counts and keyword frequencies inherit them. Treat them as good estimates, not transcription-grade output.
speakingRateWpmis words divided by video length, so long musical or silent passages pull it down. That is the honest figure for the video, not for the speech within it.- Age-restricted, private, members-only and region-locked videos cannot be read without signing in, and are reported as failures with the reason.
- Legacy
/c/Nameand/user/Namechannel URLs no longer resolve for many channels. Use the@handleor the/channel/UC…form. - View and like counts change constantly.
scrapedAtrecords when each row was taken. - This Actor reads only public pages and public feeds. It does not sign in, and cannot reach anything that requires an account.
Local development
pip install -r requirements.txtpython -m tests.test_core # 172 checks, including live requests to YouTubeapify run