YouTube Video Subtitles Scraper With Keyword Search avatar

YouTube Video Subtitles Scraper With Keyword Search

Pricing

from $4.99 / 1,000 results

Go to Apify Store
YouTube Video Subtitles Scraper With Keyword Search

YouTube Video Subtitles Scraper With Keyword Search

YouTube Video Subtitles Scraper extracts captions, subtitles, video titles, channels, and metadata from YouTube videos. Search by keywords to find relevant videos and collect subtitle data for content research, SEO, transcription, and analysis.

Pricing

from $4.99 / 1,000 results

Rating

0.0

(0)

Developer

API Empire

API Empire

Maintained by Community

Actor stats

0

Bookmarked

7

Total users

0

Monthly active users

3 days ago

Last modified

Share

YouTube Scraper — Extract Transcripts, Keyword Matches & Metadata

YouTube Video Subtitles Scraper With Keyword Search pulls the full timestamped transcript from any public YouTube video and searches it for the keywords or phrases you supply, returning every occurrence with a deep-link timestamp and its surrounding context. It also captures video metadata — title, channel, views, likes, comments, publish date, description and tags — in the same row. Every response is typed, normalized JSON: no HTML, no selectors, no manual caption-file parsing. After a run, you can search inside hundreds of transcripts for one mention without opening a single video.

It's an Apify Actor that fetches the public caption track for any YouTube video URL, converts it into a timestamped transcript, and searches that transcript for the keywords or phrases you supply — returning each match with a timestamp, a youtu.be deep link, and the surrounding text. No YouTube account or login is required; it reads the same public caption data the YouTube player itself displays, not an OAuth-gated endpoint. It's reachable as an HTTP endpoint by any script or agent framework that can call the Apify API.

  • Scrape full timestamped transcripts, with manual captions preferred and automatic captions used as the fallback
  • Scrape keyword/phrase matches inside every transcript, each with a timestamp, deep link and surrounding context
  • Scrape video metadata — title, channel, views, likes, comments, publish date, description, tags — in the same row
  • Export as JSON, CSV or any format the Apify dataset supports
  • No proxy management required — a proxy fallback ladder only switches on if YouTube starts blocking requests

What data does the YouTube Video Subtitles Scraper collect?

Each processed video is one row bundling four kinds of data: the video's own metadata, its timestamped transcript, the keyword matches found inside it, and a per-video match summary.

Data TypeKey FieldsJSON Field Names
Video metadatatitle, channel, views, likes, comments, publish date, description, tagstitle, channel_name, views, likeCount, commentCount, publishedAt, description, tags, channelId, channelUrl, length
Timestamped transcriptcaption segment start time, duration, spoken texttranscript (array of start, dur, text)
Keyword matchesmatched keyword, timestamp, deep link, surrounding contextmatches (array of keyword, matchIndex, timestampSeconds, timestampFormatted, deepLinkUrl, contextText)
Match roll-uptotal matches, matched vs. unmatched keywords, density, first/last hittotalMatches, matchedKeywords, keywordsWithNoMatches, keywordDensityPer1000Words, firstMatchTimestamp, lastMatchTimestamp, transcriptWordCount

Need more YouTube data?

If what you need is a summary of a video's content rather than its raw transcript, look for Youtube Video Summarizer By Channel & Playlist alongside this one — it condenses videos from a channel or playlist into summaries, where this Actor is built specifically for verbatim transcript text and keyword search inside it.

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

YouTube's own Data API v3 has no transcript-search endpoint at all, and its one caption-related method — captions.download — requires OAuth 2.0 authorization and edit permission on the video, so it cannot be used to pull another creator's captions; this Actor reads the same public caption track the YouTube player displays, for any public video, with no OAuth and no ownership requirement.

FeatureYouTube Data API v3YouTube Video Subtitles Scraper (this Actor)
Caption/transcript downloadcaptions.download requires OAuth 2.0 (youtube.force-ssl or youtubepartner scope) and requires the caller to have edit permission on the video (verified 2026-08-15, developers.google.com/youtube/v3/docs/captions/download)Reads the public caption track directly from the video URL — no OAuth, no video ownership needed
Keyword search inside captionsNot offered by any endpointBuilt in — every keyword/phrase match returned with timestamp, deep link and context
Video metadata lookupvideos.list, 1 quota unit per call, usable with just an API key (verified 2026-08-15, developers.google.com/youtube/v3/docs/videos/list)Metadata pulled in the same pass as the transcript, no separate metered call
Daily allocationDefault project quota: 10,000 units/day combined for all endpoints other than search.list, plus a separate 100-call/day allocation for search.list (verified 2026-08-15, developers.google.com/youtube/v3/getting-started)No API quota ledger — usage is billed per processed video under Apify's pay-per-event pricing
SetupGoogle Cloud project, API key, and (for captions) an OAuth consent flowPaste video URLs into the input and run

The Data API is the right choice if you own the videos and only need low-volume, quota-governed lookups inside Google's own infrastructure. This Actor is the right choice when you need transcript text and keyword search across videos you don't own, without setting up OAuth consent.

Why do developers and teams scrape YouTube video transcripts?

For AI engineers and agent builders

Feed transcript segments and each match's contextText into a vector store or RAG index so an agent can answer "where in this video does X happen" with a citation back to deepLinkUrl. Because matches[] is already typed with timestampSeconds and timestampFormatted, an agent tool can jump straight to a cue point instead of re-parsing a caption file, and keywordDensityPer1000Words gives it a cheap relevance signal before it spends tokens reading the full transcript.

For marketers and brand teams

Track every mention of a brand, product or campaign phrase across a batch of creator videos in one run. searchKeywords catches every variant you list, matchedKeywords versus keywordsWithNoMatches shows at a glance which videos actually discuss the topic, and keywordDensityPer1000Words ranks how much airtime a topic got relative to a video's length — without watching a single upload end to end.

For researchers and journalists

Locate a specific quote or claim inside a long interview, hearing or podcast upload by searching the transcript instead of scrubbing the timeline. timestampFormatted and deepLinkUrl jump straight to the moment for citation, and contextText gives the surrounding dialogue so a quote isn't pulled out of context.

For developers building data products

Because output field names are fixed by this Actor's own code rather than by YouTube's caption-file format, a media-monitoring dashboard, clip-finder tool or compliance-check pipeline built on top of it keeps working across YouTube's own player or caption changes. Schedule it with Apify's built-in Schedules to re-scan a channel's recent uploads for new keyword hits on a cadence.

How to scrape YouTube video transcripts (step by step)

  1. Open YouTube Video Subtitles Scraper With Keyword Search on its Apify Store page and click Try for free (or Run, if you already use it).
  2. Add one or more entries to videoUrls — standard watch?v=, short youtu.be/, or Shorts links, one per line. No field is marked required in the input schema, but the run stops immediately with a clear error message if both videoUrls and the legacy startUrls are left empty.
  3. Add searchKeywords if you want keyword matches, or leave it empty to fetch transcripts only. Set preferredCaptionLanguage, caseSensitiveSearch, wholeWordOnly, contextWindowSeconds and maxMatchesPerVideo to tune the search.
  4. Click Start — each video's row is pushed to the dataset as soon as that video finishes, not after the whole batch completes.
  5. Download results as JSON or CSV from the Storage tab, or pull them via the Apify API / apify_client.

What to do when YouTube changes its structure

YouTube periodically changes its caption-delivery and page structure. This Actor is maintained against those changes, and its output field names and types stay stable on your end — an integration built against this Actor's schema keeps working without you having to track YouTube's changes yourself.

⬇️ Input

No parameter is required — every field can be left at its default, though you need at least one entry in videoUrls (or the legacy startUrls) for the run to do anything.

ParameterRequiredTypeDescriptionExample Value
videoUrlsNoArray of stringsOne YouTube video URL per line — standard (watch?v=), short (youtu.be/), or Shorts links. Each finished video's row is written to the dataset immediately.["https://www.youtube.com/watch?v=dQw4w9WgXcQ"]
startUrlsNoArray of stringsLegacy alias of videoUrls. If both are filled, videoUrls is used first and startUrls entries are appended.[]
preferredCaptionLanguageNoStringLanguage code to prefer when a video has more than one caption track (e.g. en, es, fr). Falls back to the best available track automatically if the preferred language isn't present. Default: en."en"
languageNoStringLegacy alias of preferredCaptionLanguage, used only when it is left empty. Default: en."en"
maxWorkersNoInteger (1–10)Number of videos processed in parallel. Higher values finish a batch faster. Default: 4.4
searchKeywordsNoArray of stringsOne keyword or phrase per line to search for inside every video's transcript. Leave empty to fetch transcripts only, with no search.["never", "give you up"]
caseSensitiveSearchNoBooleanWhen true, "Music" and "music" are treated as different keywords. Default: false.false
wholeWordOnlyNoBooleanWhen true, "cat" will not match inside "category". Default: false.false
contextWindowSecondsNoInteger (0–120)Seconds of transcript before and after a match to include in that match's contextText. Default: 5.5
maxMatchesPerVideoNoInteger (minimum 0)Caps how many match rows are returned in matches[] per video (earliest first); 0 = unlimited. totalMatches, matchedKeywords and keywordDensityPer1000Words always reflect the true, uncapped count. Default: 0.0
proxyConfigurationNoObject (proxy editor)Proxy settings. Left at its default (useApifyProxy: false), the Actor runs with no proxy and only switches one on automatically if YouTube starts blocking requests.{ "useApifyProxy": false }

Example input:

{
"videoUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
"preferredCaptionLanguage": "en",
"maxWorkers": 4,
"searchKeywords": ["never", "give you up"],
"caseSensitiveSearch": false,
"wholeWordOnly": false,
"contextWindowSeconds": 5,
"maxMatchesPerVideo": 0,
"proxyConfiguration": { "useApifyProxy": false }
}

Common pitfall: maxMatchesPerVideo only trims the returned matches[] array — it never changes totalMatches, matchedKeywords, keywordsWithNoMatches or keywordDensityPer1000Words, which always reflect the true, uncapped count. Don't read a short matches[] array as the true hit count for a video.

⬆️ Output

⚠️ Every processed video is pushed to the dataset as one typed JSON row — including videos that fail (invalid URL, no transcript found, or a fetch error) — so a run over N video URLs always produces N rows, and every row is billed under the row_result charged event whether or not that video actually returned a transcript. There is no separate uncharged status row; check status and success on each row to tell a real transcript result from a skipped one. Export from the Storage tab as JSON, CSV, Excel, XML or any other format the Apify dataset supports.

Scraped video row

{
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"title": "Rick Astley - Never Gonna Give You Up (Official Video)",
"channel_name": "Rick Astley",
"length": "3:33",
"views": 1650732841,
"publishedAt": "2009-10-25T00:00:00+00:00",
"likeCount": 18234567,
"commentCount": 2345678,
"channelId": "UCuAXFkgsw1L7xaCfnd5JJOw",
"channelUrl": "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw",
"description": "The official video for “Never Gonna Give You Up” by Rick Astley...",
"tags": ["Rick Astley", "Never Gonna Give You Up", "80s"],
"transcript": [
{ "start": "18.560", "dur": "3.833", "text": "we're no strangers to love" },
{ "start": "22.393", "dur": "4.040", "text": "you know the rules and so do I" }
],
"transcriptWordCount": 612,
"matches": [
{
"keyword": "never",
"matchIndex": 1,
"timestampSeconds": 43.0,
"timestampFormatted": "0:43",
"deepLinkUrl": "https://youtu.be/dQw4w9WgXcQ?t=43",
"contextText": "never gonna give you up never gonna let you down"
}
],
"totalMatches": 7,
"matchedKeywords": ["never"],
"keywordsWithNoMatches": ["give you up"],
"keywordDensityPer1000Words": 11.44,
"firstMatchTimestamp": 43.0,
"lastMatchTimestamp": 187.5,
"status": "ok",
"message": "Transcript retrieved (subtitles).",
"success": true,
"type": "video",
"scrapedAt": "2026-08-15T09:12:03.481203+00:00"
}

status is one of ok, no_transcript, invalid_url or fetch_failed. likeCount, commentCount, views, channelId, channelUrl and publishedAt are null when YouTube does not expose them for a given video; tags defaults to an empty array, never null, when a video has none.

Keyword match shape

Each entry in matches[] is one keyword occurrence:

{
"keyword": "give you up",
"matchIndex": 2,
"timestampSeconds": 95.24,
"timestampFormatted": "1:35",
"deepLinkUrl": "https://youtu.be/dQw4w9WgXcQ?t=95",
"contextText": "never gonna give you up never gonna let you down"
}

Transcript segment shape

Each entry in transcript[] is one raw caption segment as YouTube's own caption track emits it — start and dur are string-formatted seconds, and a single spoken line can appear as several consecutive segments sharing the same start, since YouTube sometimes splits a caption line into multiple segs:

{ "start": "18.560", "dur": "3.833", "text": "we're no strangers to love" }

How does the YouTube Video Subtitles Scraper compare to other YouTube scrapers?

FeatureThis ActorGeneric alternative
Output formatTyped JSON dataset row, stable field namesRaw .vtt/.srt file or plain text you parse yourself
Keyword searchBuilt in — every match returned with timestamp, deep link and contextUsually not offered; you grep the exported transcript text yourself and lose the timestamps
Metadata + transcript in one passTitle, channel, views, likes, comments, tags returned in the same row as the transcriptTypically a separate call or tool for metadata versus captions
Legacy input supportstartUrls/language kept as working aliases so older input configs keep runningInput schema is usually fixed; renamed fields break old configs
Concurrency controlmaxWorkers (1–10) tunable per runFixed or unconfigurable concurrency

If you're building an AI agent or RAG pipeline, the output format row is the decision-maker — parsing a caption file inside an agent loop is a reliability failure mode, not a feature.

How many results can you scrape with the YouTube Video Subtitles Scraper?

There is no hard cap on how many video URLs you can submit in videoUrls/startUrls — the Actor processes every entry you give it, and each video produces exactly one dataset row. What's bounded is concurrency (maxWorkers, 1–10, default 4) and, per video, how many individual match rows are returned in matches[] (maxMatchesPerVideo, 0 = unlimited by default); that cap only trims the returned match list, never the totalMatches, matchedKeywords or keywordDensityPer1000Words summary fields, which always reflect the true count. No measured throughput benchmark is published for this Actor.

Integrate the YouTube Video Subtitles Scraper and automate your workflow

The YouTube Video Subtitles Scraper works with any language or tool that can send an HTTP request.

REST API integration

from apify_client import ApifyClient
client = ApifyClient("<APIFY_API_TOKEN>")
run = client.actor("<YOUR_USERNAME>/youtube-video-subtitles-scraper-with-keyword-search").call(
run_input={
"videoUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
"searchKeywords": ["never", "give you up"],
"contextWindowSeconds": 5,
}
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item["title"], item["totalMatches"], item["status"])

Works in Python, Node.js, Go, Ruby, cURL.

Automation platforms (n8n, Make, LangChain)

Apify publishes an official node for n8n (Run Actor / Get Dataset Items) that can call this Actor and pull its dataset into a workflow, and an equivalent app for Make. For LangChain-based agents, Apify's ApifyActorsTool / ApifyWrapper integration lets an agent invoke this Actor as a callable tool and receive the typed dataset rows directly, with no caption-file parsing step in the agent loop.

Scraping publicly available YouTube video data is generally lawful; this Actor only returns what YouTube already serves to any viewer — the caption text shown in the player's own transcript panel, and public video/channel metadata — nothing that requires a login or private access. This is public video and channel content, not personal data about a private individual, so GDPR does not attach to the data itself. What does apply is YouTube's own Terms of Service, which govern automated access to its site, and any database rights that may cover compiled result sets in your jurisdiction. Consult legal counsel for commercial use cases, particularly at high volume or when republishing scraped transcripts.

Frequently asked questions

Does the YouTube Video Subtitles Scraper work without a YouTube account?

Yes. It reads the public caption track and video page directly and needs no YouTube login or account. Apify Proxy is off by default and only switches on automatically if YouTube starts blocking requests.

How often is the scraped data updated?

Every run fetches the video's caption track and metadata live at request time — nothing is cached. The scrapedAt field on each row records when processing for that video began.

What happens when a video has no captions?

The row still comes back with status: "no_transcript", an empty transcript array, and all match-summary fields zeroed or empty — never fabricated data. success is false on that row.

Can I scrape private, age-restricted or otherwise inaccessible YouTube videos?

No. Only videos with a publicly reachable caption track and page are processed. If extraction fails — a private, deleted, or otherwise inaccessible video — the row comes back with status: "fetch_failed" and no transcript data.

Can I search for multiple keywords or phrases in one run?

Yes. Add as many lines as you need to searchKeywords; each keyword gets its own entries in matches[], and is listed in matchedKeywords if it hit at least once or keywordsWithNoMatches if it never appeared.

Do I need to write code to use this Actor?

No. Configure the input fields in the Apify Console UI and click Start — no code required. For automation, call it through the Apify API or apify_client from any language.

Does the YouTube Video Subtitles Scraper work for AI agent workflows and LLM pipelines?

Yes. It's callable as an HTTP endpoint through the Apify API by any agent framework, and every response is typed JSON with stable field names — no HTML or caption-file parsing before passing results to an LLM.

How does the YouTube Video Subtitles Scraper handle YouTube's anti-bot system?

By default it runs with no proxy at all. If a request comes back as blocked, rate-limited, or a 429/403/forbidden error, it escalates through a proxy fallback ladder — first to Apify Proxy, then to a residential proxy group — retrying up to 3 times per escalation step, with a short delay between attempts, for up to 4 total attempts per video before that video is marked fetch_failed.

Does the YouTube Video Subtitles Scraper return data in a format LLMs can use directly?

Yes. Typed, normalized JSON with stable field names — transcript segments, keyword matches, and summary fields ready to index into a vector store or pass straight into an LLM context window.

Can I use the YouTube Video Subtitles Scraper without managing proxies?

Yes. By default the Actor runs with no proxy (useApifyProxy: false) and only escalates to Apify Proxy, then a residential pool, automatically if YouTube starts blocking it — you don't need to configure your own proxy pool, though you can set proxyConfiguration explicitly if you want a specific route from the start.

What happens when YouTube changes its structure or blocks the scraper?

This Actor is maintained against YouTube's caption-delivery and page changes, and its output schema stays stable on your end — field names and types don't change because YouTube's front end did. No specific turnaround time is promised for any given fix.

Your feedback

Found a bug or missing a field? We want to know. Open an issue on this Actor's Issues tab in Apify Console, or reach out through API-Empire's contact link on the Actor's Store page.