YouTube Video Subtitles Scraper With Engagement Filters avatar

YouTube Video Subtitles Scraper With Engagement Filters

Pricing

from $2.99 / 1,000 results

Go to Apify Store
YouTube Video Subtitles Scraper With Engagement Filters

YouTube Video Subtitles Scraper With Engagement Filters

YouTube Video Subtitles Scraper — Scrape YouTube videos with subtitles, transcripts, titles, channels, views, likes, comments, and engagement metrics. Filter videos by engagement thresholds to discover high-performing content and analyze trends, topics, and audience interest.

Pricing

from $2.99 / 1,000 results

Rating

0.0

(0)

Developer

SimpleAPI

SimpleAPI

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

YouTube Subtitles Scraper — Transcripts, Views and Filters

Extract timestamped YouTube subtitles and transcripts in bulk, with views, likeCount, commentCount, engagementRate, publishedAt, and videoAgeDays on every row. This YouTube transcript scraper adds pre-fetch engagement, date, and duration filters — a video that doesn't clear your bar is reported as filtered_out and its caption request is never made. Researchers, content teams, and data pipelines use it to pull transcripts only from videos worth transcribing, without downloading media files. Point it at a list of URLs and get structured JSON back.

What is YouTube Subtitles Scraper?

YouTube Subtitles Scraper is an Apify Actor that fetches a video's timestamped caption track (manual captions when the creator uploaded them, YouTube's auto-generated captions otherwise) alongside its public metadata, and returns one JSON row per video. No YouTube account, Google Cloud project, or API key is required — it reads the same public video page and caption track a signed-out viewer's browser would.

Key features:

  • 🎬 URL-based input — paste full watch?v=, youtu.be/, or /shorts/ links, one per line
  • 📝 Timestamped transcripts — an array of {start, dur, text} segments per video, manual captions preferred, auto-generated as fallback
  • 📊 Real engagement numbersviews, likeCount, commentCount, plus derived engagementRate and videoAgeDays, honestly null when YouTube hides the count rather than a faked 0
  • 🗓️ Absolute datespublishedAt converted to ISO 8601 from YouTube's raw upload date, and a fresh scrapedAt per row
  • ⚙️ Pre-fetch filters — minimum views/likes/comments, a publish-date window, and a duration range that skip the (costlier) caption request entirely for videos that don't qualify
  • 🔁 Legacy key compatibilitystartUrls, language, and maxWorkers are still accepted as aliases

What data can I extract with YouTube Subtitles Scraper?

Every processed URL produces one row with the following fields, whether the video's captions were retrieved, filtered out, or failed.

FieldExample ValueUse Case
url"https://www.youtube.com/watch?v=dQw4w9WgXcQ"The input video URL
title"Rick Astley - Never Gonna Give You Up"Video title
channel_name"Rick Astley"Channel display name
channelId"UCuAXFkgsw1L7xaCfnd5JJOw"Canonical channel identifier
channelUrl"https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw"Channel URL
publishedAt"2009-10-25T00:00:00Z"Upload date, absolute ISO 8601 (converted from YouTube's raw upload date)
videoAgeDays6136Days between publishedAt and the moment this row was finalized
length"3:33"Duration, M:SS or H:MM:SS
views1600000000View count, null if unavailable
likeCount18000000Like count, null if hidden by the creator
commentCount2500000Comment count, null if hidden or comments disabled
engagementRate0.012813(likeCount + commentCount) / views, rounded to 6 decimals, null if views is falsy
status"success"Row outcome — success, no_transcript, fetch_error, filtered_out, invalid_input, or temporary_issue
filterReasonnullWhich pre-fetch filter excluded the video, e.g. "views below the configured minimum of 100000"; null unless status is filtered_out
transcript[{"start": "0.240", "dur": "3.360", "text": "We're no strangers to love"}]Timestamped caption segments; empty array for filtered, failed, or captionless videos
description"The official video for..."Video description, null if unavailable
tags["Rick Astley", "Never Gonna Give You Up"]Video tags, null if unavailable
message"Transcript loaded (manual captions)."Human-readable status message for this row
successtruetrue only when transcript segments were actually retrieved
type"video"Row type, always "video"
scrapedAt"2026-08-15T12:00:00Z"When this specific row was finalized, ISO 8601

📈 Engagement and timing data

views, likeCount, commentCount, engagementRate, and videoAgeDays are fetched and attached to every row — including filtered_out rows — because video metadata is retrieved before any filter is checked. This lets you compare a video's engagement against the filter thresholds you set, or build an engagement-vs-time distribution across a batch of URLs without re-running anything. engagementRate is null whenever views is 0 or unavailable, since the ratio can't be computed.

🎯 Filter results and segmentation fields

status and filterReason tell you exactly why a row looks the way it does — filter it downstream on status == "filtered_out" to see excluded videos and their reason, or status == "success" to keep only rows with a retrieved transcript. tags and channelId let you group results by topic or channel; length and videoAgeDays let you segment by duration band or recency without re-parsing dates.

How does YouTube Subtitles Scraper differ from the official YouTube Data API?

The YouTube Data API v3's captions.download method — Google's only endpoint for exporting caption text — requires OAuth 2.0 authorization from the video's owner: per Google's own documentation, "this method requires the user to have permission to edit the video," so it cannot return caption text for a video you don't own, regardless of quota (developers.google.com/youtube/v3/docs/captions/download, checked 2026-08-15).

FeatureYouTube Data API v3YouTube Subtitles Scraper
Caption text for a video you don't own❌ Not obtainable — captions.download requires OAuth with edit permission on that specific video✅ Reads the same public caption track any viewer's player loads, for any video URL
SetupGoogle Cloud project, API key, OAuth 2.0 consent flow for captionsApify account and a list of video URLs
Caption quota200 units per captions.download call, against a default 10,000 units/day per project (developers.google.com, checked 2026-08-15)Apify pay-per-event charging, no Google quota
Video metadata (views/likes/comments/duration)✅ via videos.list, API key only✅ included in every row
Pre-fetch engagement/date/duration filteringNot built in — implement client-side after fetchingminViews/minLikes/minComments/duration/date filters built in
Skips the caption request for non-qualifying videosNot applicablefiltered_out rows never trigger the caption fetch

Why can't I just use the YouTube Data API to download captions?

captions.download is the only official way to get caption text, but Google scopes it to the video's own owner: the request needs OAuth 2.0 authorization for an account with edit permission on that exact video, and costs 200 quota units against a project's default 10,000-unit daily allowance (developers.google.com, checked 2026-08-15). That rules it out for pulling captions from videos you don't control — competitor content, research corpora spanning many channels, or any third-party video. This Actor instead reads the same public caption tracks (manual or auto-generated) that YouTube's own player loads for a signed-out viewer, so no OAuth grant or channel ownership is needed.

Use the official API if you manage the channel and only need captions for your own uploads. Use this Actor when you need transcript text from videos you don't own.

How to use data extracted from YouTube video transcripts?

🔬 Researchers and NLP/dataset teams

Build a transcript corpus filtered to a minimum popularity or a recent publish window — set minViews, minLikes, and publishedAfter (e.g. "365 days"), then pull transcript and engagementRate from every row that passes. Filtered-out videos still return their metadata, so you can see exactly what was excluded and why (filterReason) without re-running the batch.

🏢 Agencies auditing channel back catalogues

Run every video URL from a client's or competitor's channel and filter the output on status == "no_transcript" to find accessibility gaps in their caption coverage, or on status == "success" with a low engagementRate to flag underperforming uploads worth a messaging review.

📊 Market research and content intelligence

Sweep a set of video URLs across a niche and correlate transcript topics against engagementRate, views, and videoAgeDays to see what content and phrasing actually drives engagement, without watching each video by hand.

🤖 AI agents and automated pipelines

Feed transcript segments into a RAG index or summarization pipeline keyed by url, or chain the Actor into a scheduled Apify run that turns a fresh list of video URLs into filtered transcript-plus-metrics data automatically.

🔼 Input sample

ParameterRequiredTypeDescriptionExample Value
youtubeUrlsNoarrayAdd full YouTube video URLs, one per line (example: https://www.youtube.com/watch?v=VIDEO_ID or https://youtu.be/VIDEO_ID). Also accepts https://www.youtube.com/shorts/VIDEO_ID.["https://www.youtube.com/watch?v=dQw4w9WgXcQ"]
startUrlsNoarrayLegacy alias of youtubeUrls, kept for input compatibility with the base actor. Use youtubeUrls above for new runs.["https://www.youtube.com/watch?v=..."]
preferredCaptionLanguageNostringLanguage code to prefer for captions (examples: en English, es Spanish, fr French). Falls back automatically to any available track when the preferred language isn't found. Default: "en"."en"
languageNostringLegacy alias of preferredCaptionLanguage, kept for input compatibility with the base actor."en"
minViewsNointegerSkip videos with fewer than this many views. 0 = no view filter. Minimum: 0. Default: 0.100000
minLikesNointegerSkip videos with fewer than this many likes (or with a hidden like count). 0 = no like filter. Minimum: 0. Default: 0.5000
minCommentsNointegerSkip videos with fewer than this many comments (or with comments disabled/hidden). 0 = no comment filter. Minimum: 0. Default: 0.100
publishedAfterNostringOnly process videos published on or after this date. Accepts an absolute date or a relative one (e.g. '30 days'). Leave empty to skip."2020-01-01"
publishedBeforeNostringOnly process videos published on or before this date. Accepts an absolute date or a relative one. Leave empty to skip."30 days"
minDurationSecondsNointegerSkip videos shorter than this many seconds. 0 = no minimum-duration filter. Minimum: 0. Default: 0.60
maxDurationSecondsNointegerSkip videos longer than this many seconds. 0 = no maximum-duration filter. Minimum: 0. Default: 0.1200
maxConcurrentRequestsNointegerNumber of videos processed in parallel (1-10). Higher values finish a batch faster. Minimum: 1. Maximum: 10. Default: 4.4
maxWorkersNointegerLegacy alias of maxConcurrentRequests, kept for input compatibility with the base actor. Minimum: 1. Maximum: 10.4
proxyConfigurationNoobjectConfigure proxy preferences for better reliability when needed. Leave default settings for normal use. Default: {"useApifyProxy": false}.{"useApifyProxy": false}
{
"youtubeUrls": [
"https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"https://www.youtube.com/watch?v=jNQXAC9IVRw"
],
"preferredCaptionLanguage": "en",
"minViews": 100000,
"publishedAfter": "2020-01-01",
"maxConcurrentRequests": 4
}

Common pitfall: all configured filters must pass together — minViews, minLikes, minComments, the duration range, and the date window are combined with AND logic, not OR. Setting minViews: 100000 and minLikes: 5000 excludes a video with 200,000 views but only 3,000 likes. Leave a filter at its default 0 (or empty, for the date fields) to remove it from the check entirely rather than trying to disable it with a low value.

🔽 Output sample

Every run produces typed, normalized JSON — one row per input URL, always pushed, whatever the outcome. Export as JSON, CSV, Excel, or any other format the Apify dataset export supports.

{
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"title": "Rick Astley - Never Gonna Give You Up",
"channel_name": "Rick Astley",
"channelId": "UCuAXFkgsw1L7xaCfnd5JJOw",
"channelUrl": "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw",
"publishedAt": "2009-10-25T00:00:00Z",
"videoAgeDays": 6136,
"length": "3:33",
"views": 1600000000,
"likeCount": 18000000,
"commentCount": 2500000,
"engagementRate": 0.012813,
"status": "success",
"filterReason": null,
"transcript": [
{ "start": "0.240", "dur": "3.360", "text": "We're no strangers to love" }
],
"description": "The official video for \"Never Gonna Give You Up\" by Rick Astley.",
"tags": ["Rick Astley", "Never Gonna Give You Up", "80s"],
"message": "Transcript loaded (manual captions).",
"success": true,
"type": "video",
"scrapedAt": "2026-08-15T12:00:00Z"
}

A video that fails a configured filter is still returned in full, without a wasted caption request:

{
"url": "https://www.youtube.com/watch?v=...",
"views": 4200,
"likeCount": 90,
"status": "filtered_out",
"filterReason": "views below the configured minimum of 100000",
"transcript": [],
"success": false,
"type": "video"
}

⚠️ Every row pushed — success, no_transcript, fetch_error, filtered_out, invalid_input, and temporary_issue alike — is charged one row_result event. Pre-fetch filtering skips the second, costlier network call (the caption fetch) for videos that don't qualify, which saves run time, but it does not exempt that row from being charged. Check the Actor's Pricing tab on the Apify Console for current per-event pricing.

How do you filter and target specific videos?

There is no keyword or category search here — targeting starts with an exact list of video URLs in youtubeUrls, so scope precision is entirely in your hands: process exactly the videos you list, nothing discovered or guessed. From there, three filter axes narrow which videos get their captions fetched at all. Quality thresholdsminViews, minLikes, minComments — skip low-engagement videos before the caption request fires. Time and duration bandspublishedAfter/publishedBefore (absolute date or a relative expression like "30 days") and minDurationSeconds/maxDurationSeconds — scope by recency or length. Volume has no schema-imposed cap: one row is produced per URL you supply, and maxConcurrentRequests (1–10) only controls how many videos are processed in parallel, not how many total. Remember all active filters combine with AND logic, so a video must clear every threshold you set, not just one.

{ "youtubeUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"], "minViews": 500000, "minLikes": 10000 }
{ "youtubeUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"], "publishedAfter": "30 days" }
{ "youtubeUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"], "minDurationSeconds": 180, "maxDurationSeconds": 1200 }

▶️ Want to try other YouTube scrapers?

Scraper NameWhat it extracts
Youtube Video Summarizer With Multi-Language TranscriptsYouTube video transcripts and summaries in multiple languages
Facebook Video Transcript Extractor By Keyword SearchFacebook video transcripts, discoverable by keyword or Page
TikTok Scraper With Repost Insights DataTikTok videos with repost insight data
Instagram Post Details Scraper With Engagement DataInstagram post details and engagement metrics

How to extract YouTube data programmatically

YouTube Subtitles Scraper runs as a standard Apify Actor: one API call starts the run, and the finished dataset comes back as structured JSON over the Apify API.

🐍 Python example

from apify_client import ApifyClient
client = ApifyClient("<APIFY_API_TOKEN>")
run = client.actor("your-username/youtube-video-subtitles-scraper-with-engagement-filters").call(
run_input={
"youtubeUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
"minViews": 100000,
"preferredCaptionLanguage": "en",
}
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item["title"], item["views"], item["status"])

🔌 MCP for AI agents

This Actor is reachable through Apify's Actors MCP Server at https://mcp.apify.com, whose call-actor tool can invoke any Apify Actor by name without pre-configuration, over either OAuth or a bearer APIFY_API_TOKEN (docs.apify.com/platform/integrations/mcp, checked 2026-08-15), for MCP clients including Cursor, VS Code, Claude Desktop, and the Apify CLI's client integrations. An agent can call it with a video URL to pull a fresh transcript and engagement snapshot as grounding context mid-conversation, without a separate integration.

📊 Export to spreadsheets or CRM

Export the dataset as CSV or Excel directly from the Apify Console or API, mapping url → a link column, title/channel_name → identifying columns, transcript → a text/notes column, and views/likeCount/commentCount/engagementRate → metric columns for import into a spreadsheet or CRM.

Scraping publicly available YouTube video pages is generally legal — this Actor only reads what YouTube already serves to a signed-out viewer, the same page a browser would load. That said, video transcripts and titles can contain personal data: names, opinions, or other identifiable information spoken or written by the people in the video, and channel_name/channelId identify the channel itself, which is often an individual creator. If you store or reuse that data, GDPR and CCPA obligations around lawful basis, retention, and deletion apply just as they would to any other personal information you collect. Consult legal counsel for commercial applications involving bulk storage of personal data.

❓ FAQ

What happens to a video that's private, deleted, or region-locked?

It's returned with status: "temporary_issue" and the message "This video's information could not be retrieved after multiple attempts." The Actor does not distinguish a permanently unavailable video from a transient connection failure — both surface with the same status and message, since the underlying fetch fails the same way in either case.

Can I get engagement data along with the transcript?

Yes — views, likeCount, commentCount, engagementRate, and videoAgeDays are fetched and attached to every row, including filtered_out rows, because metadata is retrieved before any filter is checked. A count comes back null, not 0, when YouTube hides it.

How accurate is the engagement data?

The Actor returns whatever view/like/comment counts YouTube reports to a signed-out viewer at request time — not a cached or estimated number. Accuracy depends on how current YouTube's own public counts are for that video at the moment of the run. For time-sensitive comparisons, re-run rather than reuse an older result.

How many videos can I get per run?

There's no maxItems cap in the input schema — one row is produced per URL you supply in youtubeUrls (or startUrls). maxConcurrentRequests (1–10, default 4) only controls how many videos are processed in parallel, not the total count.

Do the engagement, date, and duration filters have to all pass, or just one?

All configured filters must pass together (AND logic). A video failing any single active filter is reported filtered_out with the specific filterReason naming that filter; leave a filter at 0 (or empty for the date fields) to remove it from the check.

Does YouTube Subtitles Scraper work with Claude, ChatGPT, and AI agent frameworks?

Yes — it's reachable through Apify's Actors MCP Server (https://mcp.apify.com) for MCP-compatible clients, and callable as a standard HTTP/API endpoint via apify_client from any agent framework that can make an API call.

How does this compare to other YouTube caption scrapers?

We didn't verify specific claims from other YouTube caption scrapers' live listings for this README. What's verifiable from this Actor's own source: pre-fetch engagement/date/duration filtering that skips the caption request for videos that don't qualify, absolute (not relative) publish dates on every row, and legacy input-key compatibility (startUrls, language, maxWorkers) so existing input JSON keeps working.

Can I use this without a YouTube API key or Google developer account?

Yes. The Actor needs no YouTube Data API key, OAuth consent, or Google Cloud project — only an Apify account and the video URLs to process. It reads public caption tracks the same way a signed-out viewer's browser does, not the official captions.download endpoint.

Can I still use the legacy startUrls, language, and maxWorkers input keys?

Yes — all three are accepted as aliases of youtubeUrls, preferredCaptionLanguage, and maxConcurrentRequests, so input JSON built for the base actor keeps working unchanged.

Conclusion

YouTube Subtitles Scraper turns a list of YouTube video URLs into timestamped transcripts plus real engagement and date metadata, filtering out videos that don't meet your view, like, comment, date, or duration thresholds before their captions are ever requested. It's built for researchers and NLP teams assembling filtered transcript corpora, agencies auditing channel caption coverage, market researchers correlating content against engagement, and AI pipelines that need transcript text as grounding context. Start a run from the Apify Console or call it over the API with apify_client to get typed JSON transcripts back.