# 🎬 YouTube Transcript Scraper (`citrine_venus/youtube-transcript-scraper`) Actor

Turn any YouTube video, playlist or channel into clean, structured text. Bulk-extract transcripts and captions in 75 languages, plus views, likes, comments, keywords and thumbnails. Text array, plain text, WebVTT or SRT — ready for AI training data, RAG pipelines, summarisation and SEO.

- **URL**: https://apify.com/citrine\_venus/youtube-transcript-scraper.md
- **Developed by:** [Data Minds](https://apify.com/citrine_venus) (community)
- **Categories:** Social media, Lead generation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $7.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## 🎬 YouTube Transcript Scraper — Bulk YouTube Transcripts, Subtitles & Captions API

**YouTube Transcript Scraper** is a fast, reliable [Apify Actor](https://docs.apify.com/platform/actors) for **YouTube transcript extraction**, **YouTube subtitle scraping**, and **caption download at scale**. Paste one video link or ten thousand — plus playlists, channels, Shorts, or just a **search keyword** — and get back clean, structured transcripts together with the video details you care about: **channel name**, **channel ID**, **publish date**, **view count**, **likes**, **comments**, **keywords**, **thumbnail** and **description**.

Every video is written to your Apify **Dataset the moment its transcript is ready**, so you can export to **JSON**, **CSV**, **Excel**, or stream rows straight into **RAG pipelines**, **LLM knowledge bases**, **vector databases**, **content research**, and **SEO analysis** while the run is still going.

> 💡 **Need a custom version, a private integration, or a tailored scraper?** Email **<hello.dataminds@gmail.com>**.

***

### 📑 Table of contents

- [What is YouTube Transcript Scraper?](#-what-is-youtube-transcript-scraper)
- [Main features](#-main-features)
- [Who is this Actor for?](#-who-is-this-actor-for)
- [Built for generative AI, LLMs, and RAG](#-built-for-generative-ai-llms-and-rag)
- [What the scraper does](#%EF%B8%8F-what-the-scraper-does)
- [Supported YouTube link types](#-supported-youtube-link-types)
- [Transcript formats](#-transcript-formats)
- [Input](#-input)
- [Output format (Dataset)](#-output-format-dataset)
- [Example output (JSON)](#-example-output-json)
- [Quick start](#-quick-start)
- [Input parameters reference](#%EF%B8%8F-input-parameters-reference)
- [Integrations: LangChain, LlamaIndex, OpenAI, Pinecone, n8n](#-integrations-langchain-llamaindex-openai-pinecone-n8n)
- [Pricing & how to control cost](#-pricing--how-to-control-cost)
- [Frequently asked questions (FAQ)](#-frequently-asked-questions-faq)
- [Troubleshooting](#%EF%B8%8F-troubleshooting)
- [Help, support & custom builds](#-help-support--custom-builds)
- [Is scraping YouTube transcripts legal?](#%EF%B8%8F-is-scraping-youtube-transcripts-legal)
- [SEO keywords targeted](#-seo-keywords-targeted)

***

### 🎬 What is YouTube Transcript Scraper?

**YouTube Transcript Scraper** is a hosted **YouTube transcript API** that turns spoken video content into clean, machine-readable text. Unlike browser extensions or one-video-at-a-time tools, this Actor:

- **Handles bulk input** — a list of URLs, an uploaded file, a Google Sheet, or a whole channel.
- **Reads both caption types** — human-written subtitles *and* auto-generated captions, preferring the better one.
- **Speaks 76 languages** with a smart fallback chain, so you get a transcript instead of an empty row.
- **Returns four formats** — a clean text array, one continuous string, ready-to-use **WebVTT**, or ready-to-use **SRT**.
- **Adds video metadata** — views, likes, comments, tags, thumbnail, description, channel and publish dates.
- **Streams results live** into an Apify **Dataset**, exportable to JSON / CSV / Excel / XML or read via the [Apify API](https://docs.apify.com/api/v2).

If you have ever needed to "turn these 500 YouTube videos into text my model can read", this is the Actor.

***

### ✨ Main features

- 🔗 **True bulk input** — paste a list, upload a file, or link a Google Sheet. One URL or ten thousand, same run.
- 📺 **Channels & playlists auto-expanded** — drop in `youtube.com/@handle` or a playlist link and the Actor finds the videos for you.
- 🔍 **Search-keyword mode** — no links at all? Type `apify tutorial` and get the top matching videos' transcripts.
- 📱 **Shorts support** — include or exclude YouTube Shorts with one toggle; a Shorts link you paste yourself always works.
- 🧾 **Four transcript formats** — text array (best for AI), single-line text, **WebVTT**, and **SubRip / SRT** with real timings.
- 🌍 **76 caption languages** with automatic fallback: your language → English → whatever the video offers.
- 🗣️ **Manual *and* auto-generated captions** — human-written subtitles are preferred, auto captions used when that's all there is.
- 🎁 **Eleven optional data points** — tick only what you need, keep rows lean and runs cheap.
- 🛡️ **Built-in anti-block handling** — the run adapts automatically when YouTube pushes back, so large batches keep flowing without you configuring anything.
- 🔁 **Configurable retries** — 3 to 12 attempts per video with exponential backoff and jitter.
- ⚡ **Parallel processing** — 1 to 16 videos at a time, with a politeness delay you control.
- 💾 **Real-time Dataset writes** — a row appears the instant its transcript is ready; an aborted run still keeps everything collected so far.
- 📊 **Five prebuilt Output views** — Quick View, Transcript, Channel & Publishing, Engagement Stats, Metadata & Media.
- 🧾 **Skipped-video audit** — every video that could not be collected is written to `skipped-videos.json` with the exact reason.
- ✂️ **Oversized-row protection** — a six-hour video's transcript is trimmed to fit instead of failing the row.
- 🧹 **Automatic de-duplication** — the same video reached from two different links is only processed once.

***

### 👥 Who is this Actor for?

- 🤖 **AI engineers** building **RAG**, **retrieval-augmented generation**, and **LLM grounding** pipelines from video.
- ✍️ **Content marketers & SEO specialists** repurposing videos into blog posts, newsletters and show notes.
- 📈 **Competitive analysts** mining competitor channels for topics, positioning, and messaging.
- 🎧 **Podcasters & video creators** generating searchable archives, chapters, and subtitles.
- 🔬 **Researchers** collecting spoken-language corpora for NLP, sentiment, and discourse analysis.
- ♿ **Accessibility teams** exporting **SRT** / **VTT** subtitle files for captioning workflows.
- 📚 **Educators & students** turning lectures and tutorials into study notes.
- 🛠️ **Developers** who want a **YouTube transcript API** they can call from any language.

***

### 🤖 Built for generative AI, LLMs, and RAG

Video is the largest untapped text corpus on the web. This Actor makes it usable:

- **RAG pipelines** — chunk `captions` and embed them alongside `title` + `channelName` metadata.
- **LLM knowledge bases** — ground chatbots in webinars, tutorials, conference talks and product demos.
- **Semantic video search** — index thousands of videos so users can search *what was said*, not just titles.
- **Vector database ingestion** — drop straight into **Pinecone**, **Qdrant**, **Weaviate**, **Chroma**, **Milvus**, or **pgvector**.
- **Custom GPT / Claude Project knowledge files** — export the Dataset JSON and upload.
- **Summarization & repurposing** — feed a transcript to an LLM and get a blog post, thread, or newsletter.
- **Content moderation & compliance** — scan spoken content at scale.

#### Practical AI use cases

1. **Turn a whole YouTube channel into a chatbot knowledge base** — paste the channel URL, set a limit, embed the output.
2. **Auto-generate blog posts from webinars** — single-line text format straight into your writing prompt.
3. **Build a searchable conference-talk archive** — transcript + speaker channel + publish date per row.
4. **Competitive messaging analysis** — pull the last 100 videos from three competitor channels and diff the language.
5. **Subtitle production** — export the SRT format and ship the files.
6. **Lecture-to-notes pipelines** — playlist in, structured study notes out.
7. **Trend detection** — search-keyword mode on a schedule, then topic-model the transcripts.

***

### ⚙️ What the scraper does

- **Reads every link you give it**, separates individual videos from playlists and channels, and expands the latter into video lists (up to **Max videos per source**).
- **Runs your search keywords** and adds the top matching videos to the same queue.
- **De-duplicates** the whole queue so nothing is collected twice.
- **Pulls the best available caption track** for each video — your preferred language first, then English, then whatever exists; human-written subtitles preferred over auto-generated ones.
- **Renders the transcript** in the format you chose and attaches the optional data points you ticked.
- **Writes each row to the Apify Dataset immediately** — downstream systems can consume rows mid-run.
- **Keeps going when a video fails** — private, deleted, region-locked and caption-less videos are recorded in a skip report, never abort the run.

***

### 🔗 Supported YouTube link types

| Link type | Example | Behaviour |
|---|---|---|
| Video | `https://www.youtube.com/watch?v=Qb9s3UiMSTA` | Processed directly |
| Short link | `https://youtu.be/Qb9s3UiMSTA` | Processed directly |
| Shorts | `https://www.youtube.com/shorts/VIDEO_ID` | Processed directly |
| Live replay | `https://www.youtube.com/live/VIDEO_ID` | Processed directly |
| Playlist | `https://www.youtube.com/playlist?list=PL...` | Expanded, up to **Max videos per source** |
| Channel | `https://www.youtube.com/@handle` | Expanded, up to **Max videos per source** |
| Channel tab | `https://www.youtube.com/@handle/videos` | Expanded, up to **Max videos per source** |
| Search keyword | `apify web scraping` (in **Search keywords**) | Top results expanded |

> ℹ️ Non-YouTube links are skipped with a clear warning instead of failing the run.

***

### 🧾 Transcript formats

| `outputFormat` | `captions` value | Best for |
|---|---|---|
| `json` *(default)* | Array of caption lines — `["line one", "line two", …]` | AI, search, analytics, spreadsheets |
| `text` | One continuous, tag-free string | Summarization, LLM prompts, blog drafts |
| `vtt` | Full **WebVTT** document with `00:00:01.360 --> 00:00:03.040` timings | Web players, `<track>` elements |
| `srt` | Full **SubRip** document with numbered cues | Video editors, subtitle files |

***

### 📥 Input

Only one thing is really required: **either** at least one YouTube URL **or** at least one search keyword.

```json
{
  "urls": [
    "https://www.youtube.com/watch?v=Qb9s3UiMSTA",
    "https://www.youtube.com/@Apify"
  ],
  "searchKeywords": ["web scraping tutorial"],
  "scrapeShorts": false,
  "maxVideosPerSource": 10,
  "maxResults": 0,
  "outputFormat": "json",
  "language": "en",
  "channelNameBoolean": true,
  "channelIDBoolean": true,
  "datePublishedBoolean": true,
  "dateTextBoolean": true,
  "relativeDateTextBoolean": true,
  "viewCountBoolean": true,
  "likesBoolean": true,
  "commentsBoolean": true,
  "keywordsBoolean": true,
  "thumbnailBoolean": true,
  "descriptionBoolean": true,
  "maxConcurrency": 4,
  "requestDelaySecs": 1.0,
  "maxRetries": 8
}
```

***

### 📤 Output format (Dataset)

Results land in the default [Apify Dataset](https://docs.apify.com/platform/storage/dataset). You can:

- Browse rows in the Apify Console with **five prebuilt views** — each section of the data on its own tab.
- Export to **JSON**, **CSV**, **Excel**, **XML**, **HTML**, or **RSS**.
- Pull data programmatically via the [Apify API](https://docs.apify.com/api/v2).
- Stream into AI, ETL, or analytics pipelines while the run is still active.

#### Output views (each section of the table, separately)

| View | Columns |
|---|---|
| ✨ **Quick View** | `videoId`, `title`, `channelName`, `datePublished`, `viewCount`, `captions` |
| 📝 **Transcript** | `videoId`, `title`, `captions` |
| 📺 **Channel & Publishing** | `videoId`, `title`, `channelName`, `channelID`, `datePublished`, `dateText`, `relativeDateText` |
| 📈 **Engagement Stats** | `videoId`, `title`, `viewCount`, `likes`, `comments` |
| 🏷️ **Metadata & Media** | `videoId`, `title`, `keywords`, `thumbnailUrl`, `description` |

#### Row fields

| Field | Always present? | Description |
|---|---|---|
| `videoId` | ✅ Always | The YouTube video ID, e.g. `Qb9s3UiMSTA`. |
| `title` | ✅ Always | The video title. |
| `channelName` | Optional | Channel the video was published on. Enable **📺 Channel Name**. |
| `channelID` | Optional | The channel's unique ID. Enable **🆔 Channel ID**. |
| `datePublished` | Optional | Full ISO publish timestamp, e.g. `2024-02-22T23:00:12.000Z`. |
| `dateText` | Optional | Friendly date, e.g. `Feb 22, 2024`. |
| `relativeDateText` | Optional | Human age, e.g. `2 years ago`. |
| `viewCount` | Optional | Formatted views, e.g. `27,406,159 views`. |
| `likes` | Optional | Formatted like count, e.g. `564,840`. |
| `comments` | Optional | Formatted comment count, e.g. `30,915`. |
| `keywords` | Optional | Video tags as a comma-separated string. |
| `thumbnailUrl` | Optional | Direct link to the video thumbnail. |
| `description` | Optional | Full video description text. |
| `captions` | ✅ Always | The transcript, in the format you selected. |

> 🧾 Videos that could not be collected are written to **`skipped-videos.json`** in the run's key-value store, each with a `reason` (`No transcript available for this video`, `Private video`, `Transcript download refused (HTTP 429)`, …).

***

### 🧪 Example output (JSON)

Real output for `https://www.youtube.com/watch?v=Qb9s3UiMSTA` with every optional data point enabled (transcript abbreviated — the real row carries all 1,093 caption lines):

```json
{
  "videoId": "Qb9s3UiMSTA",
  "title": "Asyncio in Python - Full Tutorial",
  "channelName": "Tech With Tim",
  "channelID": "UC4JX40jDee_tINbkjycV4Sg",
  "datePublished": "2024-04-05T14:30:26.000Z",
  "dateText": "Apr 5, 2024",
  "relativeDateText": "2 years ago",
  "viewCount": "354,405 views",
  "likes": "9,871",
  "comments": "190",
  "keywords": "tech with tim",
  "thumbnailUrl": "https://i.ytimg.com/vi/Qb9s3UiMSTA/maxresdefault.jpg",
  "description": "Asynchronous programming allows our code to be more efficient by doing multiple things at once without any unnecessary waiting …",
  "captions": [
    "Imagine programing",
    "is a journey from point A to D.",
    "In traditional synchronous programing",
    "we travel in a straight line",
    "stopping at each point"
  ]
}
```

The same video with `"outputFormat": "srt"`:

```json
{
  "videoId": "Qb9s3UiMSTA",
  "title": "Asyncio in Python - Full Tutorial",
  "captions": "1\n00:00:00,033 --> 00:00:01,133\nImagine programing\n\n2\n00:00:01,133 --> 00:00:03,466\nis a journey from point A to D."
}
```

***

### 🚀 Quick start

#### Run in Apify Console

1. Log in at [console.apify.com](https://console.apify.com/) → **Actors**.
2. Open **YouTube Transcript Scraper**.
3. Paste your **🔗 YouTube URLs** (or type a **🔍 search keyword**).
4. Pick a **🧾 Transcript format** and a **🌍 caption language**.
5. Tick the **🎁 extra data points** you want as columns.
6. Click **Start** and watch rows stream into the **Output** tab in real time.
7. Export as **JSON / CSV / Excel**, or pull via the [Apify API](https://docs.apify.com/api/v2).

#### Run via API

```bash
curl -X POST "https://api.apify.com/v2/acts/<your-actor-id>/runs?token=<APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
        "urls": ["https://www.youtube.com/watch?v=Qb9s3UiMSTA"],
        "outputFormat": "json",
        "language": "en",
        "channelNameBoolean": true,
        "viewCountBoolean": true
      }'
```

Run it synchronously and get the rows back in one call:

```bash
curl -X POST "https://api.apify.com/v2/acts/<your-actor-id>/run-sync-get-dataset-items?token=<APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{ "urls": ["https://youtu.be/Qb9s3UiMSTA"] }'
```

Read the rows from an existing run:

```bash
curl "https://api.apify.com/v2/actor-runs/<runId>/dataset/items?format=json&token=<APIFY_TOKEN>"
```

#### Run from Python

```python
from apify_client import ApifyClient

client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("<your-actor-id>").call(run_input={
    "urls": ["https://www.youtube.com/@Apify"],
    "maxVideosPerSource": 25,
    "outputFormat": "text",
    "channelNameBoolean": True,
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["title"], "→", item["captions"][:120])
```

***

### 🛠️ Input parameters reference

| Parameter | Type | Default | Description |
|---|---|---|---|
| `urls` | array | `[]` | **YouTube links.** Videos, Shorts, `youtu.be` links, playlists, channels. Bulk-friendly: list, file upload, or Google Sheet. |
| `searchKeywords` | array | `[]` | Search terms; the top matching videos are added to the queue. Use instead of, or on top of, `urls`. |
| `scrapeShorts` | bool | `false` | Include Shorts (≤ 60 s) found inside channels, playlists and searches. Shorts you paste directly are always processed. |
| `maxVideosPerSource` | int | `10` | Videos taken from **each** playlist, channel, or keyword. Does not limit individual video links. |
| `maxResults` | int | `0` | Hard ceiling on videos processed in the whole run, after expansion and de-duplication. `0` = no limit. |
| `outputFormat` | enum | `json` | `json` (text array) · `text` (single string) · `vtt` (WebVTT) · `srt` (SubRip). |
| `language` | enum | `en` | Preferred caption language (76 options). Falls back to English, then any available track. |
| `channelNameBoolean` | bool | `false` | Add `channelName`. |
| `channelIDBoolean` | bool | `false` | Add `channelID`. |
| `datePublishedBoolean` | bool | `false` | Add `datePublished` (ISO timestamp). |
| `dateTextBoolean` | bool | `false` | Add `dateText` (`Feb 22, 2024`). |
| `relativeDateTextBoolean` | bool | `false` | Add `relativeDateText` (`2 years ago`). |
| `viewCountBoolean` | bool | `false` | Add `viewCount`. |
| `likesBoolean` | bool | `false` | Add `likes`. |
| `commentsBoolean` | bool | `false` | Add `comments`. |
| `keywordsBoolean` | bool | `false` | Add `keywords` (tags). |
| `thumbnailBoolean` | bool | `false` | Add `thumbnailUrl`. |
| `descriptionBoolean` | bool | `false` | Add `description`. |
| `maxConcurrency` | int | `4` | Videos processed in parallel (1–16). |
| `requestDelaySecs` | number | `1.0` | Polite pause before each request starts. Decimals allowed; `0` disables it. |
| `maxRetries` | int | `8` | Attempts per video before it is skipped (3–12), with exponential backoff. |

***

### 🔌 Integrations: LangChain, LlamaIndex, OpenAI, Pinecone, n8n

- 🦜 **LangChain** — load the Dataset with `ApifyDatasetLoader`, mapping `captions` → `page_content`.
- 🦙 **LlamaIndex** — feed transcripts into a `VectorStoreIndex` with `title`/`channelName` metadata.
- 🧠 **OpenAI** — chunk and embed with `text-embedding-3`, or upload as a Custom GPT knowledge file.
- 🤖 **Anthropic Claude** — attach the Dataset JSON to Claude Projects or the Files API.
- 📍 **Pinecone**, **Qdrant**, **Weaviate**, **Chroma**, **Milvus**, **pgvector** — embed and upsert with metadata filters.
- 📊 **n8n**, **Make.com**, **Zapier** — trigger runs and route transcripts into your automations.
- 📦 **Snowflake**, **BigQuery**, **PostgreSQL**, **MongoDB**, **S3** — load Dataset JSON/CSV into your warehouse.
- 🔔 **Webhooks** — get notified the moment a run finishes; see [Apify integrations](https://docs.apify.com/platform/integrations).

***

### 💸 Pricing & how to control cost

#### Billable event

| Event | When it fires | What you get |
|---|---|---|
| `transcript_result` | Once per transcript row written to the Dataset | A complete video record — transcript plus every data point you enabled |

Videos that fail, have no captions, are private/deleted, or are dropped by `maxResults` **are not charged**. If a run hits its charging limit (`ACTOR_MAX_TOTAL_CHARGE_USD`), it stops cleanly and everything already collected stays in your Dataset.

> ⚙️ **Publishing note:** the `transcript_result` event must exist in *Apify Console → your Actor → Publication → Monetization* with the same name. Until pay-per-event is configured the Actor still runs and saves data normally.

#### Keeping runs cheap

- 🎯 Set **`maxResults`** and **`maxVideosPerSource`** — the single biggest cost lever.
- 🎁 Only tick the **extra data points** you actually need.
- 🧾 Use `json` or `text` output rather than `vtt`/`srt` when you don't need timings — smaller rows.
- ⚡ Leave `maxConcurrency` at `4` unless you have a reason to change it.
- 🐢 Raise `requestDelaySecs` and lower `maxConcurrency` on very large batches — a gentler run finishes more videos on the first try.

***

### ❓ Frequently asked questions (FAQ)

**Do I need a YouTube API key?**
No. There is nothing to configure beyond the Actor input.

**Does it work on videos without subtitles?**
It works on any video that has *some* caption track — human-written or auto-generated. Videos with captions fully disabled by the uploader cannot be transcribed and are listed in `skipped-videos.json`.

**Can I scrape a whole channel?**
Yes. Paste `https://www.youtube.com/@handle` and set **Max videos per source**.

**Can I get transcripts without giving any URLs?**
Yes — use **🔍 Search keywords**.

**Which languages are supported?**
76 caption languages are selectable. If your language isn't available on a given video, the Actor falls back to English and then to any track that exists, so you still get a transcript.

**Can I download SRT or VTT subtitle files?**
Yes. Choose `srt` or `vtt` as the transcript format; the `captions` field then contains a complete, ready-to-save subtitle document.

**Are YouTube Shorts supported?**
Yes. A Shorts link you paste is always processed. To also pull Shorts found inside channels/playlists/searches, turn on **📱 Include YouTube Shorts**.

**How fast is it?**
Typically **1–3 seconds per video**, processed 4 at a time by default. A 100-video channel usually finishes in a couple of minutes.

**What happens if a video fails?**
The run continues. The failure and its reason are recorded in `skipped-videos.json`, and the summary at the end of the log shows how many videos were skipped.

**Can I run it on a schedule?**
Yes — use [Apify Schedules](https://docs.apify.com/platform/schedules), or trigger it from n8n / Make / your own backend.

**Does an aborted run lose my data?**
No. Rows are written to the Dataset as they are produced, so everything collected before the abort is already saved.

***

### 🛠️ Troubleshooting

| Symptom | Likely cause | Fix |
|---|---|---|
| `No transcript available for this video` | The uploader disabled captions entirely. | Nothing to fix — the video genuinely has no caption track. |
| Transcript is in the wrong language | The video has no track in your chosen language. | Set **🌍 Preferred caption language** to a language the video actually offers, or leave it on `en`. |
| `Private video` / `Video unavailable` | The video is private, deleted, or region-locked. | Nothing to fix — use a different link. |
| `Transcript download refused (HTTP 429)` | Rate limiting. | The Actor recovers from this on its own. To reduce it further, lower `maxConcurrency` and raise `requestDelaySecs`. |
| Channel returned fewer videos than expected | `maxVideosPerSource` or `maxResults` capped it. | Raise those limits. |
| Shorts missing from a channel run | `scrapeShorts` is off. | Turn on **📱 Include YouTube Shorts**. |
| Run saved 0 rows | No valid YouTube links, or none of the videos have captions. | Check the log — every skipped video is listed with its reason. |

***

### 🤝 Help, support & custom builds

- 💬 **Issues & feature requests** — use the **Issues** tab on the Actor page in Apify Console.
- 📧 **Direct support, custom scrapers & private integrations** — **<hello.dataminds@gmail.com>**.
- 📚 **Platform docs** — [Apify documentation](https://docs.apify.com/).

We reply to every message. If you need a variant of this Actor tuned to your workflow, just ask.

***

### ⚖️ Is scraping YouTube transcripts legal?

This Actor collects only **publicly available** information — captions and metadata that YouTube already serves to any visitor. It does not access private videos, members-only content, or anything behind a login.

That said, **you are responsible for how you use the data**. Respect copyright, YouTube's Terms of Service, and applicable law (GDPR, CCPA, and similar). Transcripts of copyrighted videos remain the property of their creators — use them for research, analysis, accessibility, or internal purposes, and seek permission before republishing. If you're unsure, talk to a lawyer.

See Apify's take: [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

***

### 🔍 SEO keywords targeted

youtube transcript scraper · youtube transcript api · youtube subtitle scraper · youtube caption downloader · bulk youtube transcript extraction · download youtube transcript · youtube transcript to text · extract youtube subtitles · youtube channel transcript scraper · youtube playlist transcript · youtube shorts transcript · youtube srt download · youtube vtt download · auto generated captions scraper · youtube video to text · transcribe youtube video · youtube transcript for AI · youtube data for RAG · youtube scraper apify · video transcript dataset · youtube metadata scraper · youtube views likes comments scraper · multilingual youtube transcripts · youtube transcript json · youtube subtitles api · youtube content research tool

# Actor input Schema

## `urls` (type: `array`):

📝 **Required (unless you use search keywords).** Paste one or more YouTube links.

✅ Supported:
• Video — `https://www.youtube.com/watch?v=VIDEO_ID`
• Short — `https://www.youtube.com/shorts/VIDEO_ID`
• Short link — `https://youtu.be/VIDEO_ID`
• Playlist — `https://www.youtube.com/playlist?list=PLAYLIST_ID`
• Channel — `https://www.youtube.com/@handle`

📺 Playlists and channels are expanded into individual videos, up to **Max videos per source** below.

## `searchKeywords` (type: `array`):

💡 No links handy? Type what you're looking for and we'll grab the transcripts of the top matching videos — e.g. `lofi hip hop`, `apify tutorial`, `python asyncio`. Results are added on top of any URLs above.

## `scrapeShorts` (type: `boolean`):

🩳 When **ON**, Shorts (videos of 60 seconds or less) found inside channels, playlists and searches are included too. When **OFF** they are skipped. A Shorts link you paste yourself is always processed.

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

🎚️ How many videos to take from **each** playlist, channel or search keyword. Individual video links are never limited by this. Keep it low for a quick, cheap test run.

## `maxResults` (type: `integer`):

🧮 A hard ceiling on how many videos the whole run will process, after everything has been expanded and de-duplicated. Leave at `0` to process every video found.

## `outputFormat` (type: `string`):

📄 Pick how the transcript is delivered in the `captions` field:

• **Text array** — one clean line per caption (best for AI, search and analytics) 🧩
• **Single line text** — the entire transcript as one continuous string 📄
• **WebVTT** — ready-to-use `.vtt` subtitles with timings 🎞️
• **SubRip (SRT)** — ready-to-use `.srt` subtitles with timings 🎬

## `language` (type: `string`):

🗣️ Which caption track to prefer. If the video has no track in this language we automatically fall back to English, then to whatever the video does offer — so you still get a transcript.

## `channelNameBoolean` (type: `boolean`):

Add the channel name the video was published on — e.g. `Selena Gomez`.

## `channelIDBoolean` (type: `boolean`):

Add the channel's unique ID — e.g. `UCjK8ORC71kwyj1DWFwril_A`.

## `datePublishedBoolean` (type: `boolean`):

Add the full publish timestamp — e.g. `2024-02-22T23:00:12.000Z`.

## `dateTextBoolean` (type: `boolean`):

Add the friendly publish date — e.g. `Feb 22, 2024`.

## `relativeDateTextBoolean` (type: `boolean`):

Add how long ago the video went live — e.g. `2 years ago`.

## `viewCountBoolean` (type: `boolean`):

Add the view count — e.g. `27,406,159 views`.

## `likesBoolean` (type: `boolean`):

Add the number of likes — e.g. `564,840`.

## `commentsBoolean` (type: `boolean`):

Add the number of comments — e.g. `30,915`.

## `keywordsBoolean` (type: `boolean`):

Add the video's tags / keywords as a comma-separated string.

## `thumbnailBoolean` (type: `boolean`):

Add a direct link to the video's thumbnail image.

## `descriptionBoolean` (type: `boolean`):

Add the full video description text.

## `maxConcurrency` (type: `integer`):

🚀 How many videos to work on at the same time. Higher is faster but pushes harder on the target. `4` is a good balance for most runs.

## `requestDelaySecs` (type: `number`):

⏱️ A polite pause before each request starts. Decimals allowed. Raise it if you are scraping a very large batch; `0` removes the pause entirely.

## `maxRetries` (type: `integer`):

🛟 How many times a single video is retried before it is skipped. Raise this if you are collecting a big batch and want the best possible success rate.

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

🌐 **Optional — leave off unless you need it.** Blocking is handled for you automatically. Only change this if your workflow requires a specific network route or country.

## Actor input object example

```json
{
  "urls": [
    "https://www.youtube.com/watch?v=Qb9s3UiMSTA"
  ],
  "searchKeywords": [],
  "scrapeShorts": false,
  "maxVideosPerSource": 10,
  "maxResults": 0,
  "outputFormat": "json",
  "language": "en",
  "channelNameBoolean": false,
  "channelIDBoolean": false,
  "datePublishedBoolean": false,
  "dateTextBoolean": false,
  "relativeDateTextBoolean": false,
  "viewCountBoolean": false,
  "likesBoolean": false,
  "commentsBoolean": false,
  "keywordsBoolean": false,
  "thumbnailBoolean": false,
  "descriptionBoolean": false,
  "maxConcurrency": 4,
  "requestDelaySecs": 1,
  "maxRetries": 8,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `items` (type: `string`):

All transcript records collected by this run.

## `skippedVideos` (type: `string`):

Videos that could not be collected, each with the reason why.

# 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 = {
    "urls": [
        "https://www.youtube.com/watch?v=Qb9s3UiMSTA"
    ],
    "searchKeywords": [],
    "maxVideosPerSource": 10,
    "maxConcurrency": 4,
    "maxRetries": 8,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("citrine_venus/youtube-transcript-scraper").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 = {
    "urls": ["https://www.youtube.com/watch?v=Qb9s3UiMSTA"],
    "searchKeywords": [],
    "maxVideosPerSource": 10,
    "maxConcurrency": 4,
    "maxRetries": 8,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("citrine_venus/youtube-transcript-scraper").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "urls": [
    "https://www.youtube.com/watch?v=Qb9s3UiMSTA"
  ],
  "searchKeywords": [],
  "maxVideosPerSource": 10,
  "maxConcurrency": 4,
  "maxRetries": 8,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call citrine_venus/youtube-transcript-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=citrine_venus/youtube-transcript-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/USQsVMGcWPAVdcvFD/builds/tRG9qlV1QvTDKQ3PB/openapi.json
