# YouTube Transcript Scraper — Channels, Playlists & AI Chunks (`vladased/youtube-transcripts-ai`) Actor

Transcripts for YouTube videos, channels, playlists & searches. Date filters, only-new mode, AI-ready chunks, SRT/VTT. Pay only for transcripts found.

- **URL**: https://apify.com/vladased/youtube-transcripts-ai.md
- **Developed by:** [obie](https://apify.com/vladased) (community)
- **Categories:** Videos, AI, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## YouTube Transcript Scraper: Channels, Playlists & AI Chunks

**Turn any YouTube channel, playlist or search into clean, timestamped transcripts in one run. Schedule it, and each run delivers
(and bills) only the new videos.** AI-ready chunks with deep links, search inside transcripts, SRT/VTT/Markdown, full metadata.
**$0.003 per transcript, and videos without captions are free.** Apify's free plan ($5/month credit) covers about 1,600 transcripts a month.

### Why this one

| | This Actor | Many transcript actors |
|---|---|---|
| Input | Videos, Shorts, channels, playlists **and YouTube searches**, mixed in one run | Video URLs (some: one channel) |
| Videos per channel / playlist | Up to 1,000 each, newest first, date filters stop paging early | Often capped at 100–200 per run |
| Scheduled runs | **Only new videos**: remembers what it delivered, so a daily run pays only for new uploads | Each run delivers and bills everything again |
| For AI / RAG | Chunks split at creator chapters, optional overlap, deep link to each second, `estimatedTokens`, one-row-per-chunk mode | Raw caption lines |
| Find mentions | **Search inside transcripts**: quoted passages with timestamps, or only videos that mention your words | Not available |
| Language | Your preference list; if missing, the video's **original** language | English-first or the first track listed |
| Failed / no captions | Listed with a machine-readable `reasonCode` and `retryable`, **never billed** | Error text, or missing from results |
| Formats | Chunks, chunk rows, segments, text, Markdown, SRT, WebVTT | 1–5 formats |

### What it does

- **Any input mix:** video URLs or IDs, Shorts, `@handles`, channel URLs, playlist URLs, and YouTube search queries.
- **Whole channels and playlists:** up to 1,000 videos per source. Channel content type: long videos, Shorts, past live streams, or everything.
- **Date filters:** `publishedAfter` / `publishedBefore` as dates or relative (`7 days`, `3 months`).
- **Only new videos:** turn it on and schedule the run daily or hourly. Each run delivers only uploads it hasn't sent you before.
  Give several inputs the same *Memory name* to share one memory.
- **Search filters:** sort by relevance/date/views/rating, upload date (last hour → year), duration (short/medium/long).
- **Find words inside transcripts:** every match comes back as a quoted passage with timestamp, chapter and a link to that second.
  *Only videos that mention them* turns the Actor into a brand/topic monitor: matching videos are delivered as usual; videos that
  don't match cost $0.001 each (we still had to fetch and search them).
- **AI / RAG ready:** ~60-second chunks (10–900 s), never crossing a creator chapter, optional overlap, each with `start`, `end`, `chapter`
  and a deep link. `chunkRows` gives one flat row per chunk (with video title, channel and date on every row), ready for Pinecone,
  Qdrant, Supabase, Google Sheets or an n8n loop.
- **Clean timing:** auto-captions overlap almost every line with the next; we clip them, so SRT/VTT show one line at a time and chunk times are exact.
- **Readable documents:** `markdown` gives title, chapters as headings and paragraphs, ready for Notion or Google Docs.
- **Metadata:** title, channel, @handle, publish date, duration, views, likes, category, keywords, description, thumbnail, chapters, word count.
  Best-effort: a field YouTube doesn't return for a video is left out rather than guessed.
- **Built to keep working:** YouTube's lightweight app API (not page scraping), automatic retries, cheapest network route first.
  Every video ends up in the results: delivered, or listed with the reason. A run that's moved between servers resumes without
  re-delivering or re-billing anything.

### Use cases

- **RAG chatbots and knowledge bases** over a creator's, company's or course's whole channel, kept fresh with *Only new videos*.
- **Brand and topic monitoring:** search YouTube daily for your product or competitors and get the exact moments they're mentioned.
- **Summaries** of podcasts, lectures, earnings calls and conference talks.
- **Content repurposing:** blog posts, newsletters, threads and show notes from videos (Markdown output).
- **Research:** what are the top videos on a topic saying? Search + transcripts + quotes with timestamps.
- **SEO and competitor analysis** of what channels in your niche talk about.

### Input

| Field | What it does |
|---|---|
| Videos, channels or playlists | Any mix of URLs, IDs and @handles (max 200). |
| Search queries | Transcripts for the top video results of each search. |
| Max videos per source | Default 10, up to 1,000. |
| Channel content | `videos` (default), `shorts`, `streams` or `all`. |
| Published after / before | Dates (`2026-01-31`) or relative (`7 days`, `2 weeks`, `3 months`). |
| Only new videos / Memory name | Skip videos earlier runs already delivered. |
| Search: sort / upload date / duration | YouTube's own search filters. |
| Find words inside transcripts / Only videos that mention them | Quoted matches with timestamps; optional filter. |
| Preferred languages | Codes in order of preference. Default `en`. |
| Prefer auto-generated captions | Off by default (human captions are more accurate). |
| Transcript format | `chunks` (default), `chunkRows`, `segments`, `text`, `markdown`, `srt`, `vtt`. |
| Chunk length / overlap (seconds) | Default 60 / 0. |
| Include video metadata | On by default. |

Switching from another transcript actor? `videoUrls`, `urls`, `startUrls`, `youtube_url`, `channel_url`, `max_videos`, `language`,
`start_date` and `end_date` work as-is.

Example: monitor three channels daily for new videos, as RAG chunks:

```json
{
  "sources": ["@lexfridman", "@hubermanlab", "https://www.youtube.com/playlist?list=PL..."],
  "maxVideosPerSource": 50,
  "onlyNewVideos": true,
  "transcriptFormat": "chunkRows",
  "chunkSeconds": 60,
  "chunkOverlapSeconds": 10
}
```

Example: who on YouTube talked about your product this week?

```json
{
  "searchQueries": ["acme analytics review"],
  "searchSort": "date",
  "searchUploadDate": "week",
  "transcriptSearch": ["acme"],
  "onlyMatchingVideos": true
}
```

### Output

One row per video (or one row per chunk with `chunkRows`). Real output for the default input:

```json
{
  "type": "transcript",
  "videoId": "wjZofJX0v4M",
  "url": "https://www.youtube.com/watch?v=wjZofJX0v4M",
  "title": "Transformers, the tech behind LLMs | Deep Learning Chapter 5",
  "channelName": "3Blue1Brown",
  "channelHandle": "@3blue1brown",
  "publishedAt": "2024-04-01T12:13:57-07:00",
  "durationSeconds": 1634,
  "viewCount": 11389186,
  "likeCount": 237290,
  "category": "Education",
  "language": "en",
  "autoGenerated": false,
  "wordCount": 5137,
  "estimatedTokens": 7278,
  "availableLanguages": [
    "ar",
    "de",
    "en",
    "es",
    "fr",
    "hi",
    "..."
  ],
  "text": "The initials GPT stand for Generative Pretrained Transformer.  ...",
  "chapters": [
    {
      "start": 0,
      "title": "Predict, sample, repeat",
      "end": 183
    },
    {
      "start": 183,
      "title": "Inside a transformer",
      "end": 396
    },
    "..."
  ],
  "chunks": [
    {
      "start": 0,
      "end": 61.06,
      "text": "The initials GPT stand for Generative Pretrained T ...",
      "url": "https://www.youtube.com/watch?v=wjZofJX0v4M&t=0s",
      "chapter": "Predict, sample, repeat"
    },
    {
      "start": 61.06,
      "end": 122.02,
      "text": "that take in a text description and produce an ima ...",
      "url": "https://www.youtube.com/watch?v=wjZofJX0v4M&t=61s",
      "chapter": "Predict, sample, repeat"
    },
    "..."
  ]
}
```

With *Find words inside transcripts* (`["attention"]`), each row also gets:

```json
{
  "matches": [
    {
      "start": 235.28,
      "matched": [
        "attention"
      ],
      "text": "This sequence of vectors then passes through an operation that's known as an attention block, and this allows the vectors to talk to each other and pass information back and forth to update their values.",
      "url": "https://www.youtube.com/watch?v=wjZofJX0v4M&t=235s",
      "chapter": "Inside a transformer"
    },
    "..."
  ]
}
```

Videos we can't deliver come as free rows you can branch on:

```json
{"type": "no_transcript", "videoId": "...", "reasonCode": "no_captions", "retryable": false, "reason": "no captions on this video"}
```

`reasonCode` is one of `no_captions`, `captions_restricted`, `age_restricted`, `private`, `members_only`, `region_blocked`, `removed`,
`unavailable`, `live_or_upcoming`, `empty_transcript`, `temporary_error`, `blocked`. `retryable: true` means a later run may succeed
(e.g. a stream that's live now gets captions after it ends).

Download as JSON, CSV, Excel or HTML, or read the dataset over the Apify API.

### Pricing

**$0.003 per transcript delivered** ($3 per 1,000), cheaper on higher Apify plans, whatever the video's length. No charge for
videos without captions, failed videos, or videos outside your date range. No compute fee on top. The only other charge: with
*Only videos that mention them* on, each video scanned without a match costs $0.001.
Examples: one video $0.003 · a 30-video channel $0.09 · a daily *only new videos* run on 3 channels ≈ $0.01.
Set a *maximum cost per run* and the Actor stops cleanly there, keeping everything already fetched.

**Speed:** a single video in seconds, about 20 videos a minute in bulk (a 1,000-video channel took 58 minutes in our test). The default run
timeout is 3 hours; if a run reaches its timeout it stops cleanly, keeps everything, and tells you how to continue.

### Integrations, schedules and AI agents

- **Schedules:** Apify Console → Schedules → run daily with *Only new videos* on.
- **n8n, Make, Zapier:** use the Apify integration ("Run Actor" + "Get dataset items"). Apify webhooks can trigger your flow when a run finishes.
- **LangChain, LlamaIndex:** Apify's document loaders read the dataset directly; `chunkRows` maps one row to one document.
- **AI agents (MCP):** available through Apify's MCP server (Claude, ChatGPT, Cursor). Tip for agents: start with `maxVideosPerSource` ≤ 10,
  read `estimatedTokens` before loading full text, and use `transcriptSearch` to get only the passages you need.

```python
from apify_client import ApifyClient
client = ApifyClient("<TOKEN>")
run = client.actor("<this actor>").call(run_input={"sources": ["@lexfridman"], "maxVideosPerSource": 10, "transcriptFormat": "chunkRows"})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(row["title"], row["start"], row["text"][:80])
```

### FAQ

**Does every video have a transcript?** No. The video needs captions (human-made or YouTube's automatic ones). Most spoken videos do;
music-only, very new or very short videos may not. You're not charged for those.

**Can it translate, or transcribe videos without captions?** No. YouTube serves translated captions only to its own player, behind a
token, and we don't fake that token. We also don't download audio. You get the caption languages a video actually has
(`availableLanguages`); if yours is missing, you get the video's original-language transcript.

**Speaker names?** YouTube captions don't say who is speaking, so no transcript tool that reads captions can give reliable speaker labels.

**Punctuation?** Human-made captions are punctuated; YouTube's automatic captions often aren't. We don't rewrite the text.

**Live streams and premieres?** Finished streams with captions work. Upcoming or ongoing ones come back as `live_or_upcoming`, free and retryable.

**Is it legal?** It reads publicly available captions, the same text YouTube shows any viewer, and it never bypasses YouTube's access
controls (no faked tokens, no logins, no private or members-only videos). You're responsible for how you use the content
(copyright and YouTube's terms). Don't use it for personal data you have no right to process.

**Something broke?** Open an issue on the Issues tab with your run link and we'll fix it fast.

### Related

Our **YouTube Scraper** (views, likes, dates, channel stats; fast mode) and **YouTube Comments Scraper** (comments, replies, filters, hot moments) take the same URLs.

# Changelog

This Actor's version history is a separate document: https://apify.com/vladased/youtube-transcripts-ai/changelog.md

# Actor input Schema

## `sources` (type: `array`):

Videos, Shorts, channels (@handle or URL), playlists, in any mix (max 200). Each transcript delivered costs $0.003; videos without captions are free. Channels give newest uploads first. Also accepts 'videoUrls', 'urls', 'startUrls' from other transcript actors.

## `searchQueries` (type: `array`):

Get transcripts for the top video results of each YouTube search.

## `maxVideosPerSource` (type: `integer`):

Cap per channel, playlist or search (1–1000). Single videos count as one. Start small; raise for bulk runs.

## `transcriptFormat` (type: `string`):

'chunks' and 'chunkRows' split at ~chunk length and at creator chapters, each with a deep link to that second. Full plain text is always included (except in chunkRows).

## `languages` (type: `array`):

Language codes in order of preference (e.g. en, es, de). 'en' also matches en-US/en-GB. If none exists, you get the video's own main transcript; 'availableLanguages' lists the rest.

## `channelContent` (type: `string`):

Which uploads to take from channels.

## `publishedAfter` (type: `string`):

Only videos published on/after this date: YYYY-MM-DD or relative like '7 days', '2 weeks', '3 months'. Works for channels, playlists and searches.

## `publishedBefore` (type: `string`):

Only videos published on/before this date (YYYY-MM-DD or relative).

## `searchSort` (type: `string`):

Order of search results. 'date' = newest first (date filters then stop paging early).

## `searchUploadDate` (type: `string`):

YouTube's upload-date filter for searches.

## `searchDuration` (type: `string`):

YouTube's duration filter for searches.

## `onlyNewVideos` (type: `boolean`):

Skip videos this input already delivered in earlier runs, so a daily schedule only pays for new uploads. Memory lives in a key-value store 'youtube-transcripts-state' in your account.

## `stateKey` (type: `string`):

Share one 'only new' memory across different inputs by giving them the same name. Empty = one memory per set of sources.

## `transcriptSearch` (type: `array`):

Words or phrases to look for (case-insensitive). Each video gets 'matches': the quoted passage, its timestamp, chapter and a link to that second. In 'chunkRows' format every chunk gets 'hasMatch'.

## `onlyMatchingVideos` (type: `boolean`):

Deliver only videos whose transcript contains at least one of the words above ($0.003 each). Videos that don't match cost $0.001 each (we still had to fetch and search them). Great for brand or topic monitoring.

## `chunkSeconds` (type: `integer`):

For AI-ready chunks: about how many seconds of speech per chunk.

## `chunkOverlapSeconds` (type: `integer`):

Each chunk also starts with the last N seconds of the previous chunk, for better retrieval in RAG. 0 = no overlap. Must be less than chunk length.

## `preferAutoGenerated` (type: `boolean`):

By default human-made captions win over YouTube's automatic ones.

## `includeMetadata` (type: `boolean`):

Title, channel, handle, publish date, duration, views, likes, category, keywords, description, thumbnail, chapters.

## `proxyConfiguration` (type: `object`):

Leave as is: the cheapest route is tried first and residential is used only if YouTube blocks it.

## Actor input object example

```json
{
  "sources": [
    "https://www.youtube.com/watch?v=wjZofJX0v4M"
  ],
  "searchQueries": [
    "how transformers work"
  ],
  "maxVideosPerSource": 10,
  "transcriptFormat": "chunks",
  "languages": [
    "en"
  ],
  "channelContent": "videos",
  "publishedAfter": "30 days",
  "searchSort": "relevance",
  "searchUploadDate": "any",
  "searchDuration": "any",
  "onlyNewVideos": false,
  "transcriptSearch": [
    "pricing",
    "open source"
  ],
  "onlyMatchingVideos": false,
  "chunkSeconds": 60,
  "chunkOverlapSeconds": 0,
  "preferAutoGenerated": false,
  "includeMetadata": true,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `overview` (type: `string`):

One row per video: title, channel, language, word count, or why there's no transcript.

## `results` (type: `string`):

Full transcripts with chunks/segments and metadata.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "sources": [
        "https://www.youtube.com/watch?v=wjZofJX0v4M"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("vladased/youtube-transcripts-ai").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "sources": ["https://www.youtube.com/watch?v=wjZofJX0v4M"] }

# Run the Actor and wait for it to finish
run = client.actor("vladased/youtube-transcripts-ai").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "sources": [
    "https://www.youtube.com/watch?v=wjZofJX0v4M"
  ]
}' |
apify call vladased/youtube-transcripts-ai --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,vladased/youtube-transcripts-ai"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/n1dXfAtKxsIjiNfAi/builds/GOUkfbnNWiTBs5ejG/openapi.json
